首页 编程 软件学院 查看内容

理解Android进程启动之全过程

2016-10-11 13:26 2416 2

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

一. 概述

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

再进一步进程是如何创建的, 可能很多人不知道fork的存在. 在我的文章 理解Android进程创建流程 集中一点详细介绍了 Process.start 的过程是如何一步步创建进程.本文则是从另个角度来全局性讲解android进程启动全过程所涉及的根脉, 先来看看AMS.startProcessLocked方法.

二. 四大组件与进程

2.1 startProcessLocked

在 ActivityManagerService.java 关于启动进程有4个同名不同参数的重载方法, 为了便于说明,以下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系列的方法;

2.2 四大组件与进程

Activity, Service, ContentProvider, BroadcastReceiver这四大组件,在启动的过程,当其所承载的进程不存在时需要先创建进程. 这个创建进程的过程是调用前面讲到的startProcessLocked方法1(a) . 调用流程: 1(a) => 1(b) ==> 2(b). 下面再简单说说这4大组件与进程创建是在何时需要创建的.

2.2.1 Activity

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

[-> 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.2.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.2.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.2.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.3 小节

Activity, Service, ContentProvider, BroadcastReceiver这四大组件在启动时,当所承载的进程不存在时,都需要创建. 进程的创建过程交由系统进程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为空则新建一个,当创建失败则直接返回;
  • 当系统未准备完毕,则将当前进程加入到mProcessesOnHold, 并直接返回;
  • 最后启动新进程,其中参数含义:
    • hostingType可取值为”activity”,”service”,”broadcast”,”content provider”;
    • hostingNameStr数据类型为ComponentName,代表的是具体相对应的组件名.

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的处理

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

返回顶部