[toc]
基于 Android 7.1.1 源码分析,进程
1 前言
我们知道,在 Android 系统中,每一个 app 都至少运行在一个进程中的,可以通过配置 Android:process 属性,来使 app 的某个组件运行在不同的进程中的,从而达到一个 app 在运行在多个进程中!
本文将总结和分析 Android 进程启动进程的主要流程,更深入地理解 Android 系统的架构!
2 启动进程的方法
AMS 中进程启动相关的方法有如下的 2 组:1
2
3
4
5
6
7
8
9
10
11
12private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
//【1】进一步调用
startProcessLocked(app, hostingType,
hostingNameStr, null /* abiOverride */,
null /* entryPoint */, null /* entryPointArgs */);
}
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
... ... ... ...
}
第一组,可以看出启动方式是通过进程的 ProcessRecord 对象来启动的!
参数传递:
- ProcessRecord app:进程对应的 ProcessRecord 对象!
- String hostingType:
- String hostingNameStr:
- String abiOverride:null
- String entryPoint:null
- String[] entryPointArgs:null
接着来看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName,
boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
// 进一步调用
return startProcessLocked(processName, info,
knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated,
0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */,null /* crashHandler */);
}
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated,
int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint,
String[] entryPointArgs, Runnable crashHandler) {
... ... ... ...
// 最后又调用了第一组方法中的第二个方法!!
startProcessLocked(app, hostingType, hostingNameStr, abiOverride,
entryPoint, entryPointArgs);
checkTime(startTime, "startProcess: done starting proc!");
return (app.pid != 0) ? app : null;
}
第二组,可以看出启动方式是通过应用的进程名和 ApplicationInfo来启动进程的!
参数传递:
- String processName:进程名字,默认为包名!
- ApplicationInfo info:进程所属应用的信息对象!
- boolean knownToBeDead:父进程是否需要在该进程死亡后接到通知!
- int intentFlags:intent 启动的 flags 参数!
- String hostingType:值为 “activity”,“service”,“broadcast” 或者 “content provider”;
- String hostingNameStr:数据类型为 ComponentName,代表的是具体相对应的组件名!
- boolean allowWhileBooting:这个在AMS的启动篇里有涉及过,表示开机时是否拉起该进程!
- boolean isolated:表示该进程是否是一个隔离进程!
- int isolatedUid:0 隔离进程的 uid!
- boolean keepIfLarge:
- String abiOverride:null
- String entryPoint:null
- String[] entryPointArgs:null
- Runnable crashHandler:null
最后,都调用了:1
2
3private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
... ... ... ...
接着,我们进入今天的正文,进程的启动!!
3 startProcessLocked - 启动
接下来,我们来看看用进程名 precessName 和应用的 ApplicationInfo 对象启动进程的方法,这个方法略微有些长,我们来仔细的分析:
1 | final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, |
继续分析!
3.1 AMS.newProcessRecordLocked
创建进程对应的 ProcessRecord 结构体,参数传递:
- ApplicationInfo info:应用程序的 info 对象!
- String customProcess:进程名
- boolean isolated:是否是隔离进程!
- int isolatedUid:隔离进程的 uid,默认传入 0!
1 | final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, |
3.1.1 AMS.addProcessNameLocked
接着,调用该方法,将新创建的 ProcessRecord 加入到 AMS 对应的集合:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private final void addProcessNameLocked(ProcessRecord proc) {
// We shouldn't already have a process under this name, but just in case we
// need to clean up whatever may be there now.
// 移除相同的之前被添加过的进程!
ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
if (old == proc && proc.persistent) {
// We are re-adding a persistent process. Whatevs! Just leave it there.
Slog.w(TAG, "Re-adding persistent process " + proc);
} else if (old != null) {
Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc);
}
// 给这个进程的所属 uid 创建 UidRecord 对象,如果已创建过了,就不创建!!
UidRecord uidRec = mActiveUids.get(proc.uid);
if (uidRec == null) {
uidRec = new UidRecord(proc.uid);
// This is the first appearance of the uid, report it now!
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
// 第一次创建时,要加入到 mActiveUids 集合中去!
mActiveUids.put(proc.uid, uidRec);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
// 添加 proc 对 UidRecord 引用!
proc.uidRecord = uidRec;
// Reset render thread tid if it was already set, so new process can set it again.
proc.renderThreadTid = 0;
// UidRecord 的被引用计数加 1
uidRec.numProcs++;
// 将新创建的 ProcessRecord 对象加入到 ams 的 ProcessNames 中!
mProcessNames.put(proc.processName, proc.uid, proc);
if (proc.isolated) {
// 如果该进程是隔离进程,还要添加到 mIsolatedProcesses 集合中去!!
mIsolatedProcesses.put(proc.uid, proc);
}
}
这里有提到 AMS 的几个成员对象:
- mActiveUids:当前活跃的 uid 集合;
- mProcessNames:以进程的 processName 为 key,存储所有的 ProcessRecord 对象!
- mIsolatedProcesses:以进程的 pid 为 key,存储所有的 ProcessRecord 对象!
4 startProcessLocked - ProcessRecord
接着们就要进入最关键的一个方法哦,启动进程!
参数传递:
- ProcessRecord app,
- String hostingType,
- String hostingNameStr:
- String abiOverride:
- String entryPoint:null
- String[] entryPointArg:null
1 | private final void startProcessLocked(ProcessRecord app, String hostingType, |
这个方法很长,我们回顾一下它的主要作用:
- 先将进程的 pid 设置为 0,
- 根据不同参数,设置相应的 debugFlags,比如在 AndroidManifest.xml 中设置 androidd:debuggable 为 true,代表 app 运行在 debug 模式,则增加 debugger 标识以及开启 JNI check 功能等等。
- 调用 Process.start 进入 Zygote,来创建新进程,并返回创建的结果 ProcessStartResult 。
- 根据 fork 的结果,再次设置 ProcessRecord 的成员变量, 包括 pid, killded,killedByAm 等等属性!
可以看出,这个方法的关键,就在于 Process.start 方法,是用来创建进程的,这个方法我们在第二篇:进程的创建一文中有讲,这里因为篇幅关系,就省略了!
接着就要进入这个新进程的 ActivityThread.main 方法了:
5 ActivityThread.main
这个方法是应用程序进程的入口:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
// 将当前进程所在 userId 赋值给 sCurrentUser
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 创建主线程的 Looper 对象!
Looper.prepareMainLooper();
// 创建该进程的 ActivityThread 对象!
ActivityThread thread = new ActivityThread();
// attach 到 ActiviyManagerService ,保持进程和 SystemServer 的 binder 通信!
// 这里我们下面重点讲!
thread.attach(false);
if (sMainThreadHandler == null) {
// 获得主线程的 Handler 对象 mH;
sMainThreadHandler = thread.getHandler();
}
if (false) { // 当设置为 true 时,可打开消息队列的 debug log 信息
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 进入消息循环,没消息进入休眠状态,有消息进入唤醒状态!
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这个方法的作用有如下:
- 创建主线程的 Looper 对象,主线程的 Looper 对象是在进程创建后自动创建的!
- 创建该进程的 ActivityThread 对象,每一个进程都有一个 ActivityThread 对象!
- mAppThread = new ApplicationThread(),创建 ApplicationThread 对象,他是应用进程和 AMS 通信的桥梁;
- mLooper = Looper.myLooper(),获得主线程的 Looper 对象;
- mH = new H(),H 继承于 Handler 对象,主线程的 Handler,用于处理组件的生命周期!
- … … …
- 获得主线程的 Handler 对象 mH:
- 进入消息循环:Looper.loop,没有消息进入休眠,有消息就被唤醒,处理消息!
注意:这里要先说一下:ActivityThread 和 ApplicationThread 对象,二者都不是线程对象!一个应用程序进程对应一个 ActivityThread 实例,应用程序进程由 ActivityThread.main 打开消息循环;同时,一个应用程序进程也对应一个 ApplicationThread 对象,此对象是 ActivityThread 与 ActivityManagerService 连接的桥梁!
6 ActivityThread.attach
参数传递:
- system:表示是否是系统进程的 ActivityThread,调用传入 false。
1 | private void attach(boolean system) { |
对于应用进程的 attach 主要流程:
- 创建线程来开启虚拟机的 JIT 即时编译。
- 通过 binder,调用到 AMS.attachApplication,其参数 mAppThread 的数据类型为 ApplicationThread。
- 观察是否快接近 heap 的上限,当已用内存超过最大内存的 3 / 4,则请求释放内存空间。
- 添加 dropbox 日志到 libcore。
- 添加 Config 回调接口。
7 ActivityManagerProxy.attachApplication
- 参数传递:IApplicationThread app,这里传入的是 ApplicationThread 对象!
1 | public void attachApplication(IApplicationThread app) throws RemoteException |
以上是在应用进程里面,下面就要通过 Binder 通信,进入系统进程中:
此处:descriptor = “android.app.IActivityManager”,用来校验使用的!
8 ActivityManagerNative.onTransact
1 |
|
通过 Binder 通信,调用 AMS 的方法:!
9 ActivityManagerService.attachApplication
1 |
|
这里简单,再获得应用进程的 pid!
10 ActivityManagerService.attachApplicationLocked
传入参数:
- ApplicationThreadProxy 对象,应用程序进程的 pid
删掉了部分的注释!
1 | private final boolean attachApplicationLocked(IApplicationThread thread, |
我们来回顾一下这个方法:
- 根据 pid 从 mPidsSelfLocked 中查询到相应的 ProcessRecord 对象 app。
- 当 app==null,意味着本次创建的进程不存在,则直接返回,这属于异常。
- 判断 app.thread 是否为 null,此时 thread 应该为 null,若不为 null 则表示该 app 附到上一个进程,则调用 handleAppDiedLocked 清理。
- 绑定死亡通知,当进程 pid 死亡时会通过 binder 死亡回调,来通知 system_server 进程死亡的消息。
- 重置 ProcessRecord 进程信息,并设置 app.thread 为新进程的 ApplicationThreadProxy ,attach 操作完成 。
- app 进程存在正在启动中的 provider,则超时 10s 后发送 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG 消息。
- 调用 thread.bindApplication 绑定应用进程,后面再进一步说明。
- 检查是否有 Provider,Activity,Service,Broadcast 等组件运行在该新进程。
10.1 new AppDeathRecipient
我们来看看死亡通知对象的创建!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp; // 进程对应的 ProcessRecord 对象!
final int mPid; // 进程的 pid
final IApplicationThread mAppThread; // 进程的 ApplicationThreadProxy 对象!
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
if (DEBUG_ALL) Slog.v(
TAG, "New death recipient " + this
+ " for thread " + thread.asBinder());
mApp = app;
mPid = pid;
mAppThread = thread;
}
public void binderDied() {
if (DEBUG_ALL) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
当进程死亡后,其对应的死亡通知对象就会收到通知,其 binderDied 方法就会被调用,接着进入 appDiedLocked 方法:
10.1 AMS.appDiedLocked
参数 fromBinderDied 置为 true!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
boolean fromBinderDied) {
// First check if this ProcessRecord is actually active for the pid.
synchronized (mPidsSelfLocked) {
ProcessRecord curProc = mPidsSelfLocked.get(pid);
if (curProc != app) {
Slog.w(TAG, "Spurious death for " + app + ", curProc for " + pid + ": " + curProc);
return;
}
}
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteProcessDiedLocked(app.info.uid, pid);
}
// 这里 killed 值为 false;
if (!app.killed) {
if (!fromBinderDied) {
Process.killProcessQuiet(pid);
}
// 杀掉进程所在的进程组!
killProcessGroup(app.uid, pid);
app.killed = true;
}
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
boolean doLowMem = app.instrumentationClass == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died");
mAllowLowerMemLevel = true;
} else {
// Note that we always want to do oom adj to update our state with the
// new number of procs.
mAllowLowerMemLevel = false;
doLowMem = false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
// 杀掉进程后继续调用 handleAppDiedLocked 方法!
handleAppDiedLocked(app, false, true);
if (doOomAdj) {
updateOomAdjLocked();
}
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
} else if (app.pid != pid) {
// A new process has already been started.
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died and restarted (pid " + app.pid + ").");
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
} else if (DEBUG_PROCESSES) {
Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
}
}
10.2 AMS.handleAppDiedLocked
- 参数 restarting 表示进程是否在重启,这里传入 false;
- 参数 allowRestart 表示是否允许进程重启,这里传入 true;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
false /*replacingPid*/);
if (!kept && !restarting) {
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileProc == app) {
clearProfilerLocked();
}
// Remove this application's activities from active lists.
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
app.activities.clear();
if (app.instrumentationClass != null) {
Slog.w(TAG, "Crash of app " + app.processName
+ " running instrumentation " + app.instrumentationClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
if (!restarting && hasVisibleActivities
&& !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
// If there was nothing to resume, and we are not already restarting this process, but
// there is a visible activity that is hosted by the process... then make sure all
// visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
10.2.1 AMS.cleanUpApplicationRecordLocked
1 | private final boolean cleanUpApplicationRecordLocked(ProcessRecord app, |
从上面可以看到,如果已经进程是 persistent 进程,死亡通知对象接收到通知后会重启这个进程!
attach 结束了,接下来,是 SystemServer 进程 bind 应用程序进程!
11 ApplicationThreadProxy.bindApplication
这里是在 SystemServer 进程中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61class ApplicationThreadProxy implements IApplicationThread {
private final IBinder mRemote;
public ApplicationThreadProxy(IBinder remote) {
mRemote = remote;
}
public final IBinder asBinder() {
return mRemote;
}
... ... ...// 省略其他暂时不需要的方法!
// 这里是 bind 操作!
public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
Bundle testArgs, IInstrumentationWatcher testWatcher,
IUiAutomationConnection uiAutomationConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
boolean persistent, Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
info.writeToParcel(data, 0);
data.writeTypedList(providers);
if (testName == null) {
data.writeInt(0);
} else {
data.writeInt(1);
testName.writeToParcel(data, 0);
}
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
data.writeBundle(testArgs);
data.writeStrongInterface(testWatcher);
data.writeStrongInterface(uiAutomationConnection);
data.writeInt(debugMode);
data.writeInt(enableBinderTracking ? 1 : 0);
data.writeInt(trackAllocation ? 1 : 0);
data.writeInt(restrictedBackupMode ? 1 : 0);
data.writeInt(persistent ? 1 : 0);
config.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
data.writeMap(services);
data.writeBundle(coreSettings);
// binder 通信!
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
... ... ...
}
参数 Map<String, IBinder> services 是通过 AMS 的 getCommonServicesLocked 方法获得的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
if (isolated) {
if (mIsolatedAppBindArgs == null) {
mIsolatedAppBindArgs = new HashMap<>();
mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
}
return mIsolatedAppBindArgs;
}
if (mAppBindArgs == null) { // 对于非隔离进程,这里会获得一些常用服务的 binder 对象!!
mAppBindArgs = new HashMap<>();
// Setup the application init args
mAppBindArgs.put("package", ServiceManager.getService("package"));
mAppBindArgs.put("window", ServiceManager.getService("window"));
mAppBindArgs.put(Context.ALARM_SERVICE,
ServiceManager.getService(Context.ALARM_SERVICE));
}
return mAppBindArgs;
}
这里的 IApplicationThread.descriptor = “android.app.IApplicationThread”
ATP 经过 binder ipc 传递到 ATN 的 onTransact 方法。
12 ApplicationThreadNative.onTransact
进入到 ATN 的 onTransact 方法中,这里进入了应用程序的进程中了:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
...
case BIND_APPLICATION_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
// 获得应用程序的包名!
String packageName = data.readString();
ApplicationInfo info =
ApplicationInfo.CREATOR.createFromParcel(data);
List<ProviderInfo> providers =
data.createTypedArrayList(ProviderInfo.CREATOR);
ComponentName testName = (data.readInt() != 0)
? new ComponentName(data) : null;
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle testArgs = data.readBundle();
IBinder binder = data.readStrongBinder();
IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
binder = data.readStrongBinder();
IUiAutomationConnection uiAutomationConnection =
IUiAutomationConnection.Stub.asInterface(binder);
int testMode = data.readInt();
boolean openGlTrace = data.readInt() != 0;
boolean restrictedBackupMode = (data.readInt() != 0);
boolean persistent = (data.readInt() != 0);
Configuration config = Configuration.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
HashMap<String, IBinder> services = data.readHashMap(null);
Bundle coreSettings = data.readBundle();
// [见流程3.11]
bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
testWatcher, uiAutomationConnection, testMode, openGlTrace,
restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
return true;
}
...
}
13 ApplicationThread.bindApplication
我们接着看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
if (services != null) {
// 这里将前面获得的系统公共 services 缓存到 ServiceManager 的 sCache 中,
// 减少 binder 检索服务的次数.
ServiceManager.initServiceCache(services);
}
// 发送消息 H.SET_CORE_SETTINGS
setCoreSettings(coreSettings);
AppBindData data = new AppBindData(); // 初始化 AppBindData
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
// 发送 H.BIND_APPLICATION 消息!
sendMessage(H.BIND_APPLICATION, data);
}
其中 setCoreSettings() 过程就是调用 sendMessage(H.SET_CORE_SETTINGS, coreSettings) 来向主线程发送 SET_CORE_SETTINGS 消息,如下:
1 | public void setCoreSettings(Bundle coreSettings) { |
总结一下:bindApplication 方法的主要功能是依次向主线程发送消息 H.SET_CORE_SETTINGS 和 H.BIND_APPLICATION。
14 ActivityThread.H - 消息处理
进入到应用程序进程的主线程 Handler “H”:
1 | private class H extends Handler { |
我们继续来看吧:
14.1 消息 H.SET_CORE_SETTINGS
处理 H.SET_CORE_SETTINGS 消息,调用 handleSetCoreSettings 方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23private void handleSetCoreSettings(Bundle coreSettings) {
synchronized (mResourcesManager) {
mCoreSettings = coreSettings;
}
onCoreSettingsChange();
}
private void onCoreSettingsChange() {
boolean debugViewAttributes =
mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
if (debugViewAttributes != View.mDebugViewAttributes) {
View.mDebugViewAttributes = debugViewAttributes;
// request all activities to relaunch for the changes to take place
// 由于发生改变, 请求所有的 activities 重启启动!
for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
false /* preserveWindow */);
}
}
}
14.2 消息 H.BIND_APPLICATION
处理 H.BIND_APPLICATION 消息,调用 handleBindApplication 方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267private void handleBindApplication(AppBindData data) {
// 将 UI 线程注册到 VMRuntime 中!
VMRuntime.registerSensitiveThread();
if (data.trackAllocation) {
DdmVmInternal.enableRecentAllocations(true);
}
// 记录进程的开始时间!
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
mProfiler = new Profiler();
if (data.initProfilerInfo != null) {
mProfiler.profileFile = data.initProfilerInfo.profileFile;
mProfiler.profileFd = data.initProfilerInfo.profileFd;
mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
}
// 设置进程名, 也就是说进程名是在进程真正创建以后的 BIND_APPLICATION 过程中才取名!
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
if (data.persistent) {
// 如果常驻进程,在低内存设备, 不采用硬件加速绘制,以节省内存使用量!
if (!ActivityManager.isHighEndGfx()) {
ThreadedRenderer.disable(false);
}
}
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
// 如果应用程序的目标 sdk 小于等于 Honeycomb MR1
// 设置 AsyncTask 默认的线程池为 THREAD_POOL_EXECUTOR!
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
// 重置进程时区为系统时区!
TimeZone.setDefault(null);
// 设置语言环境列表!
LocaleList.setDefault(data.config.getLocales());
synchronized (mResourcesManager) {
// 更新系统配置
mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
mCurDefaultDisplayDpi = data.config.densityDpi;
// This calls mResourcesManager so keep it within the synchronized block.
applyCompatConfiguration(mCurDefaultDisplayDpi);
}
// 创建应用程序的 LoadedApk 对象,每个进程都有一个。
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
// 如果需要的话,设置该进程为像素
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();
// 设置时间显示的格式!
final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
DateFormat.set24HourTimePref(is24Hr);
View.mDebugViewAttributes =
mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
// 对于 userdebug/eng 编译方式的系统应用来说,使用 dropbox 工具来分析 log 堆栈!
if ((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
// 如果应用的目标平台大于等于Honeycomb,就不允许在主线程使用网络相关功能
// 不然会抛出 NetworkOnMainThreadException 异常!
if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
StrictMode.enableDeathOnNetwork();
}
// 如果应用的目标平台不低于 Android N,那就不允许应用将 “file://” 这样的 Uri
// 直接暴露出去,比如跨包传递等等,不然会抛出 FileUriExposedException
if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
StrictMode.enableDeathOnFileUriExposure();
}
NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(
(data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0);
if (data.debugMode != IApplicationThread.DEBUG_OFF) {
// XXX should have option to change the port.
Debug.changeDebugPort(8100);
if (data.debugMode == IApplicationThread.DEBUG_WAIT) {
Slog.w(TAG, "Application " + data.info.getPackageName()
+ " is waiting for the debugger on port 8100...");
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.showWaitingForDebugger(mAppThread, true);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
Debug.waitForDebugger();
try {
mgr.showWaitingForDebugger(mAppThread, false);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "Application " + data.info.getPackageName()
+ " can be debugged on port 8100...");
}
}
// 当处于调试模式,则运行应用生成 systrace 信息
boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
Trace.setAppTracingAllowed(isAppDebuggable);
if (isAppDebuggable && data.enableBinderTracking) {
Binder.enableTracing();
}
/**
* Initialize the default http proxy in this process for the reasons we set the time zone.
*/
// 初始化默认的 http 代理!
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies");
final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
// In pre-boot mode (doing initial launch to collect password), not
// all system is up. This includes the connectivity service, so don't
// crash if we can't get it.
final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw e.rethrowFromSystemServer();
}
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Instrumentation 是谷歌提供的一个基本测试类,具有监控交互的作用!
// 每个进程都有一个 Instrumentation 对象,这里我们不看测试相关的!
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
... ... ... ...
} else {
ii = null; // 进入此分支!
}
// 创建应用的上下文实例,更新本地语言平台列表!
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
updateLocaleListFromAppContext(appContext,
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
// 对于非隔离且所属包名不是 “android”(即系统进程)的进程
// 创建缓存目录,来存放模板文集,和图形编译相关的代码!
final File cacheDir = appContext.getCacheDir();
if (cacheDir != null) {
// Provide a usable directory for temporary files
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
} else {
Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property "
+ "due to missing cache directory");
}
final Context deviceContext = appContext.createDeviceProtectedStorageContext();
final File codeCacheDir = deviceContext.getCodeCacheDir();
if (codeCacheDir != null) {
setupGraphicsSupport(data.info, codeCacheDir);
} else {
Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
}
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "NetworkSecurityConfigProvider.install");
NetworkSecurityConfigProvider.install(appContext);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Continue loading instrumentation.
if (ii != null) {
... ... ... ...
} else {
// 进入此分支,非测试情况,默认会创建一个 Instrumentation !
mInstrumentation = new Instrumentation();
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
} else {
dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
}
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
// 通过反射,创建目标应用程序的 Application 对象!
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
// 保存到 ActivityThread.mInitialApplication 中!
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
mInstrumentation.onCreate(data.instrumentationArgs);
} catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
// 调用 Application.onCreate() 回调方法.
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
}
总结一下,上面的方法的主要流程:
- 设置新进程的名字;
- 创建应用程序的 LoadedApk 对象;
- 创建应用的 ContextIpml 上下文实例;
- 创建应用程序的 Application 对象;
- 调用 Application.onCreate() 回调方法,初始化 app;
上面是这个方法的主要作用,下面我们一个一个看:
14.2.1 ContextImpl.createAppContext
创建应用程序的上下文实例,参数传递:
- ActivityThread mainThread:当前进程的 ActivityThread 对象!
- LoadedApk packageInfo:应用程序的信息对象;
1 | static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { |
这里调用了 new ContextImpl,创建了 ContextImpl 对象:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
mOuterContext = this;
mMainThread = mainThread;
mActivityToken = activityToken;
mRestricted = restricted;
if (user == null) {
user = Process.myUserHandle();
}
mUser = user;
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
? createDisplayWithId
: (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
CompatibilityInfo compatInfo = null;
if (container != null) {
compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
}
if (compatInfo == null) {
compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
mDisplayAdjustments.setConfiguration(overrideConfiguration);
mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
: ResourcesManager.getInstance().getAdjustedDisplay(displayId, mDisplayAdjustments);
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
overrideConfiguration, compatInfo);
}
}
mResources = resources;
if (container != null) {
mBasePackageName = container.mBasePackageName;
mOpPackageName = container.mOpPackageName;
} else {
mBasePackageName = packageInfo.mPackageName;
ApplicationInfo ainfo = packageInfo.getApplicationInfo();
if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
// Special case: system components allow themselves to be loaded in to other
// processes. For purposes of app ops, we must then consider the context as
// belonging to the package of this process, not the system itself, otherwise
// the package+uid verifications in app ops will fail.
mOpPackageName = ActivityThread.currentPackageName();
} else {
mOpPackageName = mBasePackageName;
}
}
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
14.2.2 LoadedApk.makeApplication
调用了 LoadedApk.makeApplication 方法,利用反射创建应用的 Application 对象,参数传入:
- boolean forceDefaultAppClass:data.restrictedBackupMode
- Instrumentation instrumentation:null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
// 如果已经创建,就直接返回!
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
// 要反射的类!
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) { // 如果应用不是 framework-res.apk
initializeJavaContextClassLoader();
}
// 创建应用的上下文实例!
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 利用上下文实例,创建应用的 Application 对象!
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
// 这里是实现 Context 和 Application 的相互引用!
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) { //这里不看!
... ... ...
}
// Rewrite the R 'constants' for all library apks.
SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
.getAssignedPackageIdentifiers();
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) {
continue;
}
rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
}
return app;
}
这里调用了 Instrumentation.newApplication 方法,创建 Application 的实例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// 继续调用 newApplication 方法!
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// 创建 Application 对象!
Application app = (Application)clazz.newInstance();
// 将 context 和 Application 绑定,我们直接通过 getApplicationContext
// 获得的就是这个 context 实例!
app.attach(context);
return app;
}
14.2.3 Instrumentation.callApplicationOnCreate
这个方法很简单:1
2
3
4
5public void callApplicationOnCreate(Application app) {
// 调用 onCreate 方法!
app.onCreate();
}
调用 Application 的 onCreate 方法!
到这里,bind 操作也完成了,应用程序进程已经启动,并且完成了和 SystemServer 进程的双向 Binder 绑定,也创建了应用程序的 Application 对象,调用了Application.onCreate 方法,接下来,就是启动指定的组件了!
回到 ActivityManagerService.attachApplicationLocked 方法中,bind 成功后,就会检测新进程中的组件了,组件的启动就在那里!!
关于组件的启动,以后在说!!
15 总结
其实,我们可以看到,进程的启动和创建,还是相当复杂的,其中涉及的细节很多,当时,阅读源码,最忌讳死扣细节,我们需要对框架有个整体的理解,下面,我们来通过几张图来总结一下,进程的启动!!
15.1 进程的创建和启动
下面我们用一张图来回顾下这个流程:
其中,check/start 指定组件,也存在系统进程和应用进程间的多次 Binder 通信,这里我们不重点讨论,在后面分析四大组件时,会详细分析他们的生命周期过程,会重点分析这个部分!