Android 四大组件与进程启动的关系

一. 概述

Android系统将进程做得很友好的封装,对于上层app开发者来说进程几乎是透明的. 了解Android的朋友,一定知道Android四大组件,但对于进程可能会相对较陌生. 一个进程里面可以跑多个app(通过share uid的方式), 一个app也可以跑在多个进程里(通过配置Android:process属性).

再进一步进程是如何创建的, 可能很多人不知道fork的存在. 在我的文章理解Android进程创建流程 集中一点详细介绍了Process.start的过程是如何一步步创建进程.

进程承载着整个系统,"进程之于Android犹如水之于鱼", 进程对于Android系统非常重要, 对于android来说承载着Android四大组件,承载着系统的正常运转. 本文则跟大家聊一聊进程的,是从另个角度来全局性讲解android进程启动全过程所涉及的根脉, 先来看看AMS.startProcessLocked方法.

二. 四大组件与进程

2.1 四大组件

Activity, Service, ContentProvider, BroadcastReceiver这四大组件,在启动的过程,当其所承载的进程不存在时需要调用startProcessLocked先创建进程

2.1.1 Activity

启动Activity过程: 调用startActivity,该方法经过层层调用,最终会调用ActivityStackSupervisor.java中的startSpecificActivityLocked,当activity所属进程还没启动的情况下,则需要创建相应的进程.更多关于Activity, 见startActivity启动过程分析

[-> ActivityStackSupervisor.java]

  • void startSpecificActivityLocked(...) {
  • ProcessRecord app = mService.getProcessRecordLocked(r.processName,
  • r.info.applicationInfo.uid, true);
  • if (app != null && app.thread != null) {
  • ... //进程已创建的case
  • return
  • }
  • mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
  • "activity", r.intent.getComponent(), false, false, true);
  • }

2.1.2 Service

启动服务过程: 调用startService,该方法经过层层调用,最终会调用ActiveServices.java中的bringUpServiceLocked,当Service进程没有启动的情况(app==null), 则需要创建相应的进程. 更多关于Service, 见startService启动过程分析

[-> ActiveServices.java]

  • private final String bringUpServiceLocked(...){
  • ...
  • ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
  • if (app == null) {
  • if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
  • "service", r.name, false, isolated, false)) == null) {
  • ...
  • }
  • }
  • ...
  • }

2.1.3 ContentProvider

ContentProvider处理过程: 调用ContentResolver.query该方法经过层层调用, 最终会调用到AMS.java中的getContentProviderImpl,当ContentProvider所对应进程不存在,则需要创建新进程. 更多关于ContentProvider,见理解 ContentProvider 原理

[-> AMS.java]

  • private final ContentProviderHolder getContentProviderImpl(...) {
  • ...
  • ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);
  • if (proc != null && proc.thread != null) {
  • ... //进程已创建的case
  • } else {
  • proc = startProcessLocked(cpi.processName,
  • cpr.appInfo, false, 0, "content provider",
  • new ComponentName(cpi.applicationInfo.packageName,cpi.name),
  • false, false, false);
  • }
  • ...
  • }

2.1.4 Broadcast

广播处理过程: 调用sendBroadcast,该方法经过层层调用, 最终会调用到BroadcastQueue.java中的processNextBroadcast,当BroadcastReceiver所对应的进程尚未启动,则创建相应进程. 更多关于broadcast, 见Android Broadcast广播机制分析.

[-> BroadcastQueue.java]

  • final void processNextBroadcast(boolean fromMsg) {
  • ...
  • ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
  • info.activityInfo.applicationInfo.uid, false);
  • if (app != null && app.thread != null) {
  • ... //进程已创建的case
  • return
  • }
  • if ((r.curApp=mService.startProcessLocked(targetProcess,
  • info.activityInfo.applicationInfo, true,
  • r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
  • "broadcast", r.curComponent,
  • (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
  • == null) {
  • ...
  • }
  • ...
  • }

2.2 进程启动

ActivityManagerService.java关于启动进程有4个同名不同参数的重载方法StartProcessLocked, 为了便于说明,以下4个方法依次记为1(a),1(b), 2(a), 2(b) :

  • //方法 1(a)
  • final ProcessRecord startProcessLocked(
  • String processName, ApplicationInfo info, boolean knownToBeDead,
  • int intentFlags, String hostingType, ComponentName hostingName,
  • boolean allowWhileBooting, boolean isolated, boolean keepIfLarge)
  • //方法 1(b)
  • 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)
  • //方法 2(a)
  • private final void startProcessLocked(
  • ProcessRecord app, String hostingType, String hostingNameStr)
  • //方法 2(b)
  • private final void startProcessLocked(
  • ProcessRecord app, String hostingType, String hostingNameStr,
  • String abiOverride, String entryPoint, String[] entryPointArgs)
  • **1(a) ==> 1(b):** 方法1(a)将isolatedUid=0,其他参数赋值为null,再调用给1(b)
  • final 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 */);
  • }

2(a) ==> 2(b): 方法2(a)将其他3个参数abiOverride,entryPoint, entryPointArgs赋值为null,再调用给2(b)

  • private final void startProcessLocked(ProcessRecord app,
  • String hostingType, String hostingNameStr) {
  • startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
  • null /* entryPoint */, null /* entryPointArgs */);
  • }

小结:

  • 1(a),1(b)的第一个参数为String类型的进程名processName,
  • 2(a), 2(b)的第一个参数为ProcessRecord类型进程记录信息ProcessRecord;
  • 1系列的方法最终调用到2系列的方法;

四大组件所在应用首次启动时, 调用startProcessLocked方法1(a),之后再调用流程: 1(a) => 1(b) ==> 2(b).

2.3 启动时机

刚解说了4大组件与进程创建的调用方法,那么接下来再来说说进程创建的触发时机有哪些?如下:

  • 单进程App:对于这种情况,那么app首次启动某个组件时,比如通过调用startActivity来启动某个app,则先会触发创建该app进程,然后再启动该Activity。此时该app进程已创建,那么后续再该app中内部启动同一个activity或者其他组件,则都不会再创建新进程(除非该app进程被系统所杀掉)。
  • 多进程App: 对于这种情况,那么每个配置过android:process属性的组件的首次启动,则都分别需要创建进程。再次启动同一个activity,其则都不会再创建新进程(除非该app进程被系统所杀掉),但如果启动的是其他组件,则还需要再次判断其所对应的进程是否存在。

大多数情况下,app都是单进程架构,对于多进程架构的app一般是通过在AndroidManifest.xml中android:process属性来实现的。

  • 当android:process属性值以":"开头,则代表该进程是私有的,只有该app可以使用,其他应用无法访问;
  • 当android:process属性值不以”:“开头,则代表的是全局型进程,但这种情况需要注意的是进程名必须至少包含“.”字符。

接下来,看看PackageParser.java来解析AndroidManiefst.xml过程就明白进程名的命名要求:

  • public class PackageParser {
  • ...
  • private static String buildCompoundName(String pkg,
  • CharSequence procSeq, String type, String[] outError) {
  • String proc = procSeq.toString();
  • char c = proc.charAt(0);
  • if (pkg != null && c == ':') {
  • if (proc.length() < 2) {
  • //进程名至少要有2个字符
  • return null;
  • }
  • String subName = proc.substring(1);
  • //此时并不要求强求 字符'.'作为分割符号
  • String nameError = validateName(subName, false, false);
  • if (nameError != null) {
  • return null;
  • }
  • return (pkg + proc).intern();
  • }
  • //此时必须字符'.'作为分割符号
  • String nameError = validateName(proc, true, false);
  • if (nameError != null && !"system".equals(proc)) {
  • return null;
  • }
  • return proc.intern();
  • }
  • private static String validateName(String name, boolean requireSeparator,
  • boolean requireFilename) {
  • final int N = name.length();
  • boolean hasSep = false;
  • boolean front = true;
  • for (int i=0; i<N; i++) {
  • final char c = name.charAt(i);
  • if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
  • front = false;
  • continue;
  • }
  • if (!front) {
  • if ((c >= '0' && c <= '9') || c == '_') {
  • continue;
  • }
  • }
  • //字符'.'作为分割符号
  • if (c == '.') {
  • hasSep = true;
  • front = true;
  • continue;
  • }
  • return "bad character '" + c + "'";
  • }
  • if (requireFilename && !FileUtils.isValidExtFilename(name)) {
  • return "Invalid filename";
  • }
  • return hasSep || !requireSeparator
  • ? null : "must have at least one '.' separator";
  • }
  • }

看完上面的源码.很显然对于android:process属性值不以”:“开头的进程名必须至少包含“.”字符。

2.4 小节

Activity, Service, ContentProvider, BroadcastReceiver这四大组件在启动时,当所承载的进程不存在时,包括多进程的情况,则都需要创建。

四大组件的进程创建方法:

组件 创建方法
Activity ASS.startSpecificActivityLocked()
Service ActiveServices.bringUpServiceLocked()
ContentProvider AMS.getContentProviderImpl()
Broadcast BroadcastQueue.processNextBroadcast()

进程的创建过程交由系统进程system_server来完成的.

简称:

  • ATP: ApplicationThreadProxy
  • AT: ApplicationThread (继承于ApplicationThreadNative)
  • AMP: ActivityManagerProxy
  • AMS: ActivityManagerService (继承于ActivityManagerNative)

图解:

  1. system_server进程中调用startProcessLocked方法,该方法最终通过socket方式,将需要创建新进程的消息告知Zygote进程,并阻塞等待Socket返回新创建进程的pid;
  2. Zygote进程接收到system_server发送过来的消息, 则通过fork的方法,将zygote自身进程复制生成新的进程,并将ActivityThread相关的资源加载到新进程app process,这个进程可能是用于承载activity等组件;
  3. 创建完新进程后fork返回两次, 在新进程app process向servicemanager查询system_server进程中binder服务端AMS,获取相对应的Client端,也就是AMP. 有了这一对binder c/s对, 那么app process便可以通过binder向跨进程system_server发送请求,即attachApplication()
  4. system_server进程接收到相应binder操作后,经过多次调用,利用ATP向app process发送binder请求, 即bindApplication.

system_server拥有ATP/AMS, 每一个新创建的进程都会有一个相应的AT/AMS,从而可以跨进程 进行相互通信. 这便是进程创建过程的完整生态链.

三. 进程启动全过程

前面刚已介绍四大组件的创建进程的过程是调用1(a) startProcessLocked方法,该方法会再调用1(b)方法. 接下来从该方法开始往下讲述.

3.1 AMS.startProcessLocked

  • 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) {
  • long startTime = SystemClock.elapsedRealtime();
  • ProcessRecord app;
  • if (!isolated) {
  • //根据进程名和uid检查相应的ProcessRecord
  • app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
  • if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
  • //如果当前处于后台进程,检查当前进程是否处于bad进程列表
  • if (mBadProcesses.get(info.processName, info.uid) != null) {
  • return null;
  • }
  • } else {
  • //当用户明确地启动进程,则清空crash次数,以保证其不处于bad进程直到下次再弹出crash对话框。
  • mProcessCrashTimes.remove(info.processName, info.uid);
  • if (mBadProcesses.get(info.processName, info.uid) != null) {
  • mBadProcesses.remove(info.processName, info.uid);
  • if (app != null) {
  • app.bad = false;
  • }
  • }
  • }
  • } else {
  • //对于孤立进程,无法再利用已存在的进程
  • app = null;
  • }
  • //当存在ProcessRecord,且已分配pid(正在启动或者已经启动),
  • // 且caller并不认为该进程已死亡或者没有thread对象attached到该进程.则不应该清理该进程
  • if (app != null && app.pid > 0) {
  • if (!knownToBeDead || app.thread == null) {
  • //如果这是进程中新package,则添加到列表
  • app.addPackage(info.packageName, info.versionCode, mProcessStats);
  • return app;
  • }
  • //当ProcessRecord已经被attached到先前的一个进程,则杀死并清理该进程
  • killProcessGroup(app.info.uid, app.pid);
  • handleAppDiedLocked(app, true, true);
  • }
  • String hostingNameStr = hostingName != null? hostingName.flattenToShortString() : null;
  • if (app == null) {
  • // 创建新的Process Record对象
  • app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
  • if (app == null) {
  • return null;
  • }
  • app.crashHandler = crashHandler;
  • } else {
  • //如果这是进程中新package,则添加到列表
  • app.addPackage(info.packageName, info.versionCode, mProcessStats);
  • }
  • //当系统未准备完毕,则将当前进程加入到mProcessesOnHold
  • if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) {
  • if (!mProcessesOnHold.contains(app)) {
  • mProcessesOnHold.add(app);
  • }
  • return app;
  • }
  • // 启动进程【见小节3.2】
  • startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
  • return (app.pid != 0) ? app : null;
  • }

主要功能:

  • 对于非isolated进程,则根据进程名和uid来查询相应的ProcessRecord结构体. 如果当前进程处于后台且当前进程处于mBadProcesses列表,则直接返回;否则清空crash次数,以保证其不处于bad进程直到下次再弹出crash对话框。

  • 当存在ProcessRecord,且已分配pid(正在启动或者已经启动)的情况下
    • 当caller并不认为该进程已死亡或者没有thread对象attached到该进程.则不应该清理该进程,则直接返回;
    • 否则杀死并清理该进程;
  • 当ProcessRecord为空则新建一个,当创建失败则直接返回;

  • 当以下3个值都为false,则将当前进程加入到mProcessesOnHold, 并直接返回; 当进程真正创建则从mProcessesOnHold中移除.

    • 当AMS.systemReady()执行完成,则mProcessesReady=true;
    • 当进程为persistent, 则isAllowedWhileBooting =true;
    • 一般地创建进程时参数allowWhileBooting = false, 只有AMS.startIsolatedProcess该值才为true;
  • 最后启动新进程,其中参数含义:
    • hostingType可取值为"activity","service","broadcast","content provider";
    • hostingNameStr数据类型为ComponentName,代表的是具体相对应的组件名.

另外, 进程uid是在进程真正创建之前调用newProcessRecordLocked方法来获取的uid, 这里会考虑是否为isolated的情况.

3.2 AMS.startProcessLocked

  • private final void startProcessLocked(ProcessRecord app, String hostingType,
  • String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
  • long startTime = SystemClock.elapsedRealtime();
  • //当app的pid大于0且不是当前进程的pid,则从mPidsSelfLocked中移除该app.pid
  • if (app.pid > 0 && app.pid != MY_PID) {
  • synchronized (mPidsSelfLocked) {
  • mPidsSelfLocked.remove(app.pid);
  • mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
  • }
  • app.setPid(0);
  • }
  • //从mProcessesOnHold移除该app
  • mProcessesOnHold.remove(app);
  • updateCpuStats(); //更新cpu统计信息
  • try {
  • try {
  • if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) {
  • //当前package已被冻结,则抛出异常
  • throw new RuntimeException("Package " + app.info.packageName + " is frozen!");
  • }
  • } catch (RemoteException e) {
  • throw e.rethrowAsRuntimeException();
  • }
  • int uid = app.uid;
  • int[] gids = null;
  • int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
  • if (!app.isolated) {
  • int[] permGids = null;
  • try {
  • //通过Package Manager获取gids
  • final IPackageManager pm = AppGlobals.getPackageManager();
  • permGids = pm.getPackageGids(app.info.packageName, app.userId);
  • MountServiceInternal mountServiceInternal = LocalServices.getService(
  • MountServiceInternal.class);
  • mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
  • app.info.packageName);
  • } catch (RemoteException e) {
  • throw e.rethrowAsRuntimeException();
  • }
  • //添加共享app和gids,用于app直接共享资源
  • if (ArrayUtils.isEmpty(permGids)) {
  • gids = new int[2];
  • } else {
  • gids = new int[permGids.length + 2];
  • System.arraycopy(permGids, 0, gids, 2, permGids.length);
  • }
  • gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
  • gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
  • }
  • //根据不同参数,设置相应的debugFlags
  • ...
  • app.gids = gids;
  • app.requiredAbi = requiredAbi;
  • app.instructionSet = instructionSet;
  • boolean isActivityProcess = (entryPoint == null);
  • if (entryPoint == null) entryPoint = "android.app.ActivityThread";
  • //请求Zygote创建新进程[见3.3]
  • Process.ProcessStartResult startResult = Process.start(entryPoint,
  • app.processName, uid, uid, gids, debugFlags, mountExternal,
  • app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
  • app.info.dataDir, entryPointArgs);
  • ...
  • if (app.persistent) {
  • Watchdog.getInstance().processStarted(app.processName, startResult.pid);
  • }
  • //重置ProcessRecord的成员变量
  • app.setPid(startResult.pid);
  • app.usingWrapper = startResult.usingWrapper;
  • app.removed = false;
  • app.killed = false;
  • app.killedByAm = false;
  • //将新创建的进程加入到mPidsSelfLocked
  • synchronized (mPidsSelfLocked) {
  • this.mPidsSelfLocked.put(startResult.pid, app);
  • if (isActivityProcess) {
  • Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
  • msg.obj = app;
  • //延迟发送消息PROC_START_TIMEOUT_MSG
  • mHandler.sendMessageDelayed(msg, startResult.usingWrapper
  • ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
  • }
  • }
  • } catch (RuntimeException e) {
  • app.setPid(0); //进程创建失败,则重置pid
  • }
  • }
  • 根据不同参数,设置相应的debugFlags,比如在AndroidManifest.xml中设置androidd:debuggable为true,代表app运行在debug模式,则增加debugger标识以及开启JNI check功能
  • 调用Process.start来创建新进程;
  • 重置ProcessRecord的成员变量, 一般情况下超时10s后发送PROC_START_TIMEOUT_MSG的handler消息;

关于Process.start()是通过socket通信告知Zygote创建fork子进程,创建新进程后将ActivityThread类加载到新进程,并调用ActivityThread.main()方法。详细过程见理解Android进程创建流程,接下来进入AT.main方法.

3.3 ActivityThread.main

[-> ActivityThread.java]

  • public static void main(String[] args) {
  • //性能统计默认是关闭的
  • SamplingProfilerIntegration.start();
  • //将当前进程所在userId赋值给sCurrentUser
  • Environment.initForCurrentUser();
  • EventLogger.setReporter(new EventLoggingReporter());
  • AndroidKeyStoreProvider.install();
  • //确保可信任的CA证书存放在正确的位置
  • final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
  • TrustedCertificateStore.setDefaultUserDirectory(configDir);
  • Process.setArgV0("<pre-initialized>");
  • //创建主线程的Looper对象, 该Looper是不运行退出
  • Looper.prepareMainLooper();
  • //创建ActivityThread对象
  • ActivityThread thread = new ActivityThread();
  • //建立Binder通道 【见流程3.4】
  • thread.attach(false);
  • if (sMainThreadHandler == null) {
  • sMainThreadHandler = thread.getHandler();
  • }
  • // 当设置为true时,可打开消息队列的debug log信息
  • if (false) {
  • Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
  • }
  • Looper.loop(); //消息循环运行
  • throw new RuntimeException("Main thread loop unexpectedly exited");
  • }
  • 创建主线程的Looper对象: 该Looper是不运行退出. 也就是说主线程的Looper是在进程创建完成时自动创建完成,如果子线程也需要创建handler通信过程,那么就需要手动创建Looper对象,并且每个线程只能创建一次.
  • 创建ActivityThread对象thread = new ActivityThread(): 该过程会初始化几个很重要的变量:
    • mAppThread = new ApplicationThread()
    • mLooper = Looper.myLooper()
    • mH = new H(), H继承于Handler;用于处理组件的生命周期.
  • attach过程是当前主线程向system_server进程通信的过程, 将thread信息告知AMS.接下来还会进一步说明该过程.
  • sMainThreadHandler通过getHandler(),获取的对象便是mH,这就是主线程的handler对象.

之后主线程调用Looper.loop(),进入消息循环状态, 当没有消息时主线程进入休眠状态, 一旦有消息到来则唤醒主线程并执行相关操作.

3.4. ActivityThread.attach

[-> ActivityThread.java]

  • private void attach(boolean system) {
  • sCurrentActivityThread = this;
  • mSystemThread = system;
  • if (!system) {
  • //开启虚拟机的jit即时编译功能
  • ViewRootImpl.addFirstDrawHandler(new Runnable() {
  • @Override
  • public void run() {
  • ensureJitEnabled();
  • }
  • });
  • android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());
  • RuntimeInit.setApplicationObject(mAppThread.asBinder());
  • //创建ActivityManagerProxy对象
  • final IActivityManager mgr = ActivityManagerNative.getDefault();
  • try {
  • //调用基于IActivityManager接口的Binder通道【见流程3.5】
  • mgr.attachApplication(mAppThread);
  • } catch (RemoteException ex) {
  • }
  • //观察是否快接近heap的上限
  • BinderInternal.addGcWatcher(new Runnable() {
  • @Override public void run() {
  • if (!mSomeActivitiesChanged) {
  • return;
  • }
  • Runtime runtime = Runtime.getRuntime();
  • long dalvikMax = runtime.maxMemory();
  • long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
  • if (dalvikUsed > ((3*dalvikMax)/4)) {
  • mSomeActivitiesChanged = false;
  • try {
  • //当已用内存超过最大内存的3/4,则请求释放内存空间
  • mgr.releaseSomeActivities(mAppThread);
  • } catch (RemoteException e) {
  • }
  • }
  • }
  • });
  • } else {
  • ...
  • }
  • //添加dropbox日志到libcore
  • DropBox.setReporter(new DropBoxReporter());
  • //添加Config回调接口
  • ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
  • @Override
  • public void onConfigurationChanged(Configuration newConfig) {
  • synchronized (mResourcesManager) {
  • if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
  • if (mPendingConfiguration == null ||
  • mPendingConfiguration.isOtherSeqNewer(newConfig)) {
  • mPendingConfiguration = newConfig;
  • sendMessage(H.CONFIGURATION_CHANGED, newConfig);
  • }
  • }
  • }
  • }
  • @Override
  • public void onLowMemory() {
  • }
  • @Override
  • public void onTrimMemory(int level) {
  • }
  • });
  • }

对于非系统attach的处理流程:

  • 创建线程来开启虚拟机的jit即时编译;
  • 通过binder, 调用到AMS.attachApplication, 其参数mAppThread的数据类型为ApplicationThread
  • 观察是否快接近heap的上限,当已用内存超过最大内存的3/4,则请求释放内存空间
  • 添加dropbox日志到libcore
  • 添加Config回调接口

3.5 AMP.attachApplication

[-> ActivityManagerProxy.java]

  • public void attachApplication(IApplicationThread app) throws RemoteException
  • {
  • Parcel data = Parcel.obtain();
  • Parcel reply = Parcel.obtain();
  • data.writeInterfaceToken(IActivityManager.descriptor);
  • data.writeStrongBinder(app.asBinder());
  • mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0); //【见流程3.6】
  • reply.readException();
  • data.recycle();
  • reply.recycle();
  • }

此处 descriptor = "android.app.IActivityManager"

3.6 AMN.onTransact

[-> ActivityManagerNative.java]
```java
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
...
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
//获取ApplicationThread的binder代理类 ApplicationThreadProxy
IApplicationThread app = ApplicationThreadNative.asInterface(
data.readStrongBinder());
if (app != null) {
attachApplication(app); //此处是ActivityManagerService类中的方法 【见流程3.7】
}
reply.writeNoException();
return true;
}
}

top Created with Sketch.