
普通Activity的启动就是通过调用startActivity方法启动一个新的Activity,总体流程如下图:
其中涉及到了两个进程,一个是App进程和AMS进程。整体的步骤是:
1启动者Activity向Instrumentation请求启动目标的Activity。
2 Instrumentation通过AMS在App进程的IBinder接口(IActivityManager)访问AMS,此时App进程会阻塞等待AMS的调用返回,采用的跨进程通信技术是AIDL。
3AMS会进行一系列的验证工作,如判断目标Activity实例是否存在、启动模式是什么、有没有在AndroidManifest中注册等等。
4当AMS验证结束后会通过ClinentLifeCycleManager发送事物给App进程,利用App进程在AMS进程的IBinder接口(IApplicationThread)访问App进程ApplicationThread,采用的跨进程通信方式是AIDL。
5ApplicationThread是ActivityThread的内部类,当ApplicationThread接受到来自AMS的事务后,会将事务直接转交给ActivityThread处理。
6ActivityThread通过Instrumentation利用类加载器(反射)进行实例的创建,同时利用Instrumentation回调目标Activity的生命周期。
介绍几个关键的类:
Instrumentation:Instrumentation 是 Activity 与外界联系的类(不是 Activity 本身的类都统称为外界)。目标 Activity 通过 Instrumentation 来请求启动,ActivityThread 通过 Instrumentation 来创建 Activity 和回调 Activity 的生命周期。
ActivityThread:每个应用程序只有一个唯一实例,负责对 Activity 创建的管理。ActivityThread 的内部类 ApplicationThread 只负责 App 进程和 AMS 进程的通信,将来自 AMS 的事务交给 ActivityThread 处理。
AMS,全称 ActivityManagerService,系统级服务,负责管理四大组件。
根Actvity就是我们点击手机桌面图标时,应用程序启动的第一个Activity。启动根Activity的流程其实和启动普通Activity的流程类似,只是启动根Activity时需要新建一个App进程。总体流程如下图:
其中涉及到四个进程分别是:Launcher进程、AMS进程、App进程、Zygote进程。
1点击桌面图标后,Launcher进程访问AMS进程请求启动目标Activity,采用的跨进程方式是AIDL。
2 AMS进程访问Zygote进程请求启动一个新的进程。采用的跨进程方式是Socket。
3 Zygote进程通过调用fork函数创建一个App进程。
4 App进程创建完成后,App进程访问AMS进程进行通知,采用的跨进程方式是AIDL。
5 AMS进程收到来自App进程的通知后,将启动Activity的 *** 作封装成事务,并将封装好的事务发送给App进程。
6 App进程接受到来自AMS进程的事务后,根据事务创建目标Activity,并回调目标Activity的生命周期。
本文主要是用来记录自己的学习笔记,看原文请移步: Activity 启动流程
如果你要定制一个Android系统,你想用你自己的Launcher(Home)作主界面来替换Android自带的Home,而且不希望用户安装的Launcher来替换掉你的Launcher,应该如何来实现呢?
我们可以通过修改Framework层来实现这样的功能。
1) 首先了解一下Android的启动过程。
Android系统的启动先从Zygote开始启动,然后(中间的过程就不说了)一直到了SystemServer(framework)这个地方,看到这段代码:
/
This method is called from Zygote to initialize the system This willcause the native
services (SurfaceFlinger, AudioFlinger, etc) to be started Afterthat it will call back
up into init2() to start the Android services
/
native public static void init1(String[] args);
public static void main(String[] args) {
if (SamplingProfilerIntegrationisEnabled()) {
SamplingProfilerIntegrationstart();
timer = new Timer();
timerschedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegrationwriteSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage
VMRuntimegetRuntime()setTargetHeapUtilization(08f);
SystemloadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Logi(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thrsetName("androidserverServerThread");
thrstart();
}
}
从SystemServer的main函数开始启动各种服务:
首先启动init1,然后启动init2从上面的注释可以看到:init1这个方法时被Zygote调用来初始化系统的,init1会启动native的服务如SurfaceFlinger,AudioFlinger等等,这些工作做完以后会回调init2来启动Android的service。
这里我们主要来关注init2的过程。init2中启动ServerThread线程,ServerThread中启动了一系列的服务,比如这些:
ActivityManagerService
EntropyService
PowerManagerService
TelephonyRegistry
PackageManagerService
AccountManagerService
BatteryService
HardwareService
Watchdog
SensorService
BluetoothService
StatusBarService
ClipboardService
InputMethodManagerService
NetStatService
ConnectivityService
AccessibilityManagerService
NotificationManagerService
MountService
DeviceStorageMonitorService
LocationManagerService
SearchManagerService
FallbackCheckinService
WallpaperManagerService
AudioService
BackupManagerService
AppWidgetService
这些大大小小的服务起来以后,开始
((ActivityManagerService)ActivityManagerNativegetDefault())systemReady()
在systemReady后开始开始启动Launcher。在寻找Launcher的时候是根据HOME的filter(在Manifest中定义的<categoryandroid:name="androidintentcategoryHOME" />)来过滤。
然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了HOME,那就会d出来一个列表供用户选择。
我们现在希望从这里d出我们自己定制的Launcher,同时也不希望d出选择HOME的界面,我们不希望用户修改我们的home,比如我们的home上放了好多广告,以及强制安装的程序,不希望用户把它干掉。
我们可以通过这样来实现:
2) 定义一个私有的filter选项,然后用这个选项来过滤HOME
一般情况下我们使用Manifest中定义的<categoryandroid:name="androidintentcategoryHOME"来过滤的,我们现在增加一个私有的HOME_FIRST过滤。
在Intentjava(frameworks/base/core/java/android/content/Intentjava)中添加两行代码
//lixinso:添加CATEGORY_FS_HOME
@SdkConstant(SdkConstantTypeINTENT_CATEGORY)
public static final String CATEGORY_FS_HOME= "androidintentcategoryFS_HOME";
3)修改和CATEGORY_HOME相关的所有的地方,都改成CATEGORY_FS_HOME,主要是framework中的这几个地方:使用grep命令查找要修改的地方:
grep CATEGORY_HOME -l -R
将上述文件中和CATEGORY_HOME相关的所有的地方,都改成CATEGORY_FS_HOME。
4) 写一个自己的Launcher
可以参考android sample中的Launcher,或者android源代码中的 /packages/apps/Launcher 来写。
在Launcher中标记其是不是Launcher的最关键的代码时Manifest中的filter:android:name="androidintentcategoryHOME"
现在我们定义了自己的filter,那么,我们在我们自己写的Launcher中将Manifest改为:
<application android:process="androidprocessacore3"android:icon="@drawable/icon"android:label="@string/app_name">
<activity android:name="FirstAppActivity"
android:label="@string/app_name">
<intent-filter>
<actionandroid:name="androidintentactionMAIN" />
<categoryandroid:name="androidintentcategory FS_HOME" />
<categoryandroid:name="androidintentcategoryDEFAULT" />
<category android:name="androidintentcategoryMONKEY"/>
</intent-filter>
</activity>
</application>
然后将编译好的apk放到方式fs100_root/system/app目录下。
5)将Android自带的Launcher删除掉
包括源代码(packages/apps/Launcher)和apk(/out/target/product/generic/system/app/Launcherapk)。
6) 重新编译Android
做完这些工作,就可以重新编译Android了,我们可以编译修改过的几个相关的包,可以用mmm命令来编译部分的改动。这里需要这样编译:
$ source build/envsetupsh
$ lunch
$ mmm frameworks/base
$ mmm frameworks/base/services/java
$ mmm frameworks/policies/base/mid
$ mmm frameworks/policies/base/phone
重新启动开发板,从开发板上就可以看到启动的Launcher是我们自己的Launcher,不会出现默认的Launcher了,也不会出现选择界面。
9)我们再验证一下,如果用户装上了一个其他的Launcher(Home)会怎么样。
从网上找一个一般的Launcher或者自己写一个一般的Launcher装上去,重新启动,不会出现选择界面。
按HOME键也不会出来两个HOME来选择。
这样我们就牢牢控制了用户的桌面。
只有我们自己定制的HOME才能装上。这对于定制Android设备的厂商很有用处。
以上就是关于Activity启动流程笔记全部的内容,包括:Activity启动流程笔记、android怎么在launcher前启动一个应用程序、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)