美文网首页Android面试专栏Android源码分析
Android App启动流程浅谈(上)——Android 9.

Android App启动流程浅谈(上)——Android 9.

作者: 酷酷的Demo | 来源:发表于2019-06-19 10:52 被阅读3次

    系统在开机后的一系列行为中,最后一阶段AMS会调用Launcher来展示所有已经安装的APP,那么当我们点击图标到APP启动,最后app的一个activity展示到我们的眼前,这中间到底是如何工作的呢,本文会从源码中的主干代码从整体上理解代码的执行流程。

    整个流程图

    这张图看起来很复杂是不是,我们用文字来大致的跑一边流程:

    1. 当点击桌面App的时候,发起进程就是Launcher所在的进程,启动远程进程,利用Binder发送消息给system_server进程
    2. 在system_server进程中启动了N多服务,例如ActiivityManagerService,WindowManagerService等。启动进程的操作会先调用AMS.startProcessLocked方法,内部调用 Process.start(android.app.ActivityThread);而后通过socket通信告知Zygote进程fork子进程,即app进程。进程创建后将ActivityThread加载进去,执行ActivityThread.main()方法
    3. 在app进程中,main方法会实例化ActivityThread,同时创建ApplicationThread,Looper,Hander对象,调用attach方法进行Binder通信,looper启动循环。attach方法内部获取ActivityManagerProxy对象,其实现了IActivityManager接口,作为客户端调用attachApplication(mAppThread)方法,将thread信息告知AMS
    4. 在system_server进程中,AMS中会调用ActivityManagerNative.onTransact方法,真正的逻辑在服务端AMS.attachApplication方法中,内部调用AMS.attachApplicationLocked方法,方法的参数是IApplicationThread,在此处是ApplicationThreadProxy对象,用于跟前面通过Process.start()所创建的进程中ApplicationThread对象进行通信。
      attachApplicationLocked方法会处理Provider, Activity, Service, Broadcast相应流程,调用ApplicationThreadProxy.bindApplication方法,通过Binder通信,传递给ApplicationThreadNative.onTransact方法
    5. 在app进程中,真正的逻辑在ActivityThread.bindApplication方法中。bindApplication方法的主要功能是依次向主线程发送消息H.SET_CORE_SETTINGS 和H.BIND_APPLICATION。后续创建Application,Context等。Activity的回调也会是通过Binder通信,然后发送不同消息处理。
      这里我们在用一张图来总结一下这段话:

    Luancher——AMS

    调用过程分析

    源码地址
    frameworks/base/services/core/java/com/android/server/am/

    • ActivityManagerService.java
    • ActivityStackSupervisor.java
    • ActivityStack.java
    • ActivityRecord.java
    • ProcessRecord.java

    frameworks/base/core/java/android/app/

    • IActivityManager.java

    • ActivityManagerNative.java (内含AMP)
      -ActivityManager.java

    • IApplicationThread.java

    • ApplicationThreadNative.java (内含ATP)

    • ActivityThread.java (内含ApplicationThread)

    • ContextImpl.java

    当我们点击桌面上的图标是,App就由Luancher开始启动,Luancher也是一个应用程序,继承于Activity。Luancher也实现了点击、长按等回调接口,所以当我们点击图标时,Luancher会捕捉点击事件,然后startActivity(intent),是不是跟我们普通activity的使用差不多呢:
    App图标的点击事件会从Launcher.java中调用onClick方法:

    public void onClick(View v) {
        ...
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            // 从快捷方式图标启动
            onClickAppShortcut(v);
        } else if (tag instanceof FolderInfo) {
            // 文件夹
            if (v instanceof FolderIcon) {
               onClickFolderIcon(v);
            }
        } else if (v == mAllAppsButton) {
            // “所有应用”按钮
            onClickAllAppsButton(v);
        } else if (tag instanceof AppInfo) {
            // 从“所有应用”中启动的应用
            startAppShortcutOrInfoActivity(v);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            // 组件
            if (v instanceof PendingAppWidgetHostView) {
                onClickPendingWidget((PendingAppWidgetHostView) v);
            }
        }
    }
    

    1. Launcher.onClickAppShortcut

    我们这里先分析从快捷图标点进去的代码

    /**
         * Event handler for an app shortcut click.
         *
         * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
         */
        protected void onClickAppShortcut(final View v) {
           
            Object tag = v.getTag();
            if (!(tag instanceof ShortcutInfo)) {
                throw new IllegalArgumentException("Input must be a Shortcut");
            }
    
            // Open shortcut
            final ShortcutInfo shortcut = (ShortcutInfo) tag;
    
            if (shortcut.isDisabled != 0) {
                if ((shortcut.isDisabled &
                        ~ShortcutInfo.FLAG_DISABLED_SUSPENDED &
                        ~ShortcutInfo.FLAG_DISABLED_QUIET_USER) == 0) {
                    //如果应用程序仅因上述标志而被禁用,则无论如
                    //何都会启动活动。框架将告诉用户应用程序暂停的原因。
                   
                } else {
                    if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
                        // Use a message specific to this shortcut, if it has one.
                        Toast.makeText(this, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
                        return;
                    }
                    // Otherwise just use a generic error message.
                    int error = R.string.activity_not_available;
                    if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
                        error = R.string.safemode_shortcut_error;
                    } else if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_BY_PUBLISHER) != 0 ||
                            (shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_LOCKED_USER) != 0) {
                        error = R.string.shortcut_not_available;
                    }
                    Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
                    return;
                }
            }
    
            // Check for abandoned promise
            if ((v instanceof BubbleTextView) && shortcut.isPromise()) {
                String packageName = shortcut.intent.getComponent() != null ?
                        shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
                if (!TextUtils.isEmpty(packageName)) {
                    onClickPendingAppItem(v, packageName,
                            shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
                    return;
                }
            }
    
            // 启动Activity
            startAppShortcutOrInfoActivity(v);
        }
    

    忽略前面的代码,我们发现在onClickAppShortcut方法里又调用了 startAppShortcutOrInfoActivity方法。那我们继续再看:

    private void startAppShortcutOrInfoActivity(View v) {
            ItemInfo item = (ItemInfo) v.getTag();
            Intent intent = item.getIntent();
            if (intent == null) {
                throw new IllegalArgumentException("Input must have a valid intent");
            }
            boolean success = startActivitySafely(v, intent, item);
            getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
    
            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        }
    

    这里又调用了startActivitySafely方法:

    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
            ······
            //启动新的任务栈
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (v != null) {
                intent.setSourceBounds(getViewBounds(v));
            }
            try {
                ······
                if (user == null || user.equals(Process.myUserHandle())) {
                    // 启动活动
                    startActivity(intent, optsBundle);
                } else {
                    LauncherAppsCompat.getInstance(this).startActivityForProfile(
                            intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
                }
                return true;
            } catch (ActivityNotFoundException|SecurityException e) {
               ······
            }
            return false;
        }
    

    这里的代码比较长,我们分别来看,去除前面的一些判断,我们看到intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)这行代码。说到应用程序的Activity,他默认是MainActivity,就是你在AndroidManifest.xml文件里配置的Activity:

    <activity android:name=".MainActivity"  
          android:label="@string/app_name">  
           <intent-filter>  
            <action android:name="android.intent.action.MAIN" />  
            <category android:name="android.intent.category.LAUNCHER" />  
        </intent-filter>  
    </activity>
    

    所以这个intent包含的信息为action = "android.intent.action.Main",category="android.intent.category.LAUNCHER", cmp="shy.luo.activity/.MainActivity",他表示要启动的Activity为shy.luo.MainActivity.这里的Intent.FLAG_ACTIVITY_NEW_TASK表示要在一个新的Task中来启动这个Activity,这个Task是Android中的概念,简单地说,他是一个Activity的集合,这个集合是一个堆栈的形式,遵循先进后出。再看startActivity方法。

    2. Activity.startActivity

    站在巨人的肩膀上:startActivity启动分析移步这里

    Launcher继承于Activity类,而Activity类实现了startActivity函数,因此,这里就调用了Activity.startActivity函数,它实现在frameworks/base/core/java/android/app/Activity.java文件中:

    public class Activity extends ContextThemeWrapper
            implements LayoutInflater.Factory,
            Window.Callback, KeyEvent.Callback,
            OnCreateContextMenuListener, ComponentCallbacks {
        ......
     
        @Override
        public void startActivity(Intent intent) {
            startActivityForResult(intent, -1);
        }
        ......
    }
    

    这个函数实现很简单,它调用startActivityForResult来进一步处理,第二个参数传入-1表示不需要这个Actvity结束后的返回结果.

    3. Activity.startActivityForResult

    public void startActivityForResult(Intent intent, int requestCode) {
            //mParent是当前Acitivity的父类,此时条件成立
            if (mParent == null) {
            // 调用 Instrumentation 的 execStartActivity 方法
                Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode);
                if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            //此时requestCode =-1
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
             cancelInputsAndStartExitTransition(options);
            } else {
                if (options != null) {
                    mParent.startActivityFromChild(this, intent, requestCode, options);
                } else {
                    mParent.startActivityFromChild(this, intent, requestCode);
                }
            }
    }
    public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
                int requestCode, @Nullable Bundle options) {
            ...
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, child,
                    intent, requestCode, options);
            ...
        }
    
    
    • mInstrumentation: Activity类的成员变量,类型是Intrumentation,用来监控应用程序和系统的交互。
    • mMainThread:Activity类的成员变量,类型是ActivityThread,它代表的是应用程序的主线程,通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,是一个Binder对象,后面我们会看到,ActivityManagerService会使用它来和ActivityThread来进行进程间通信。这里我们需注意的是,这里的mMainThread代表的是Launcher应用程序运行的进程
    • mToken:Activity类的成员变量,类型为IBinder,一个Binder对象的远程接口。

    Instrumentation这个类里面的方法大多数和Application和Activity有关,这个类就是完成对Application和Activity初始化和生命周期的工具类。Instrumentation这个类很重要,对Activity生命周期方法的调用根本就离不开他,每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个Instrumentation对象.ActivityThread,依赖于UI线程。App和AMS是通过Binder传递信息的,那么ActivityThread就是专门完成与AMS的外交工作的

    Instrumentation.execStartActivity

    Instrumentation调用ActivityManagerService的startActivity

    public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
    
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ...
    
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        //当该monitor阻塞activity启动,则直接返回
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            //检查activity是否启动成功
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
    

    Activity的startActivity会调用startActivityForResult。当应用已经启动时,会先调用startActivityFromChild。但是无论应用是否启动,最后都会调用Instrumentation.execStartActivity。
    正如前面所说,ActivityManagerService实现了IActivityManager.aidl接口,提供了应用进程调用系统服务的方法,而Instrumentation包装了ActivityManagerService的调用。

    在看startActivity方法前,我们看看这里的ActivityManager.getService()方法做了什么。这里返回的是一个AMP对象,根据IPC我们知道当服务端和客户端通信时,需要一个代理类来根据是否在同一个进程,来实现通信的方式(需不需要跨进程),而Luancher App所在的进程和AMS所在进程显然不同,所以返回了包装Binder的代理对象AMP。

    Android IPC机制在整个启动流程源码中使用了很多,对于IPC机制还不了解的可以先看看这篇IPC基础速成,之后再去仔细学习。

     @UnsupportedAppUsage
        public static IActivityManager getService() {
            return IActivityManagerSingleton.get();
        }
    

    IActivityManagerSingleton是一个静态变量:

    @UnsupportedAppUsage
        private static final Singleton<IActivityManager> IActivityManagerSingleton =
                new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                     // 向 ServiceManager 查询一个 key 为 Context.ACTIVITY_SERVICE" 的引用
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    

    ServiceManager 是 Binder IPC 通信过程的核心,是上下文的管理者,Binder 服务端必须先向 ServerManager 注册才能够为客户端提供服务,Binder 客户端在与服务端通信之前需要从 ServerManager 中查找并获取 Binder 服务端的引用。

    这里通过 "Context.ACTIVITY_SERVICE" 这个名字向 ServiceManager 查询 AMS 的引用,获取 AMS 的引用后,调用 asInterface 方法:

    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        // 根据 descriptor 查询 obj 是否为 Binder 本地对象(是否在同一进程)
        IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        // 如果 obj 不是 Binder 本地对象,则将其包装成代理对象并返回
        return new ActivityManagerProxy(obj);
    }
    

    所以最终返回了AMP这个代理类,再往下看:

    AMP.startActivity方法参数传递的每一项对应值:

    • caller: 当前应用的ApplicationThread对象mAppThread,他是一个Binder实体;
    • callingPackage:调用当前ContextImpl.getBasePackageName(),获取当前Activity所在包名;
    • intent: 这便是启动Activity时,传递过来的参数;
    • resolvedType: 调用intent.resolveTypeIfNeeded而获取;
    • resultTo: 来自于当前Activity.mToken
    • resultWho: 来自于当前Activity.mEmbeddedID
    • requestCode = -1;
    • startFlags = 0;
    • profilerInfo = null;
    • options = null;

    AMP.startActivity

    class ActivityManagerProxy implements IActivityManager
    {
       public ActivityManagerProxy(IBinder remote)
       {
           mRemote = remote;
       }
    
       public IBinder asBinder()
       {
           return mRemote;
       }
    
      public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
           Parcel data = Parcel.obtain();
           Parcel reply = Parcel.obtain();
           data.writeInterfaceToken(IActivityManager.descriptor);
           data.writeStrongBinder(caller != null ? caller.asBinder() : null);
           data.writeString(callingPackage);
           intent.writeToParcel(data, 0);
           data.writeString(resolvedType);
           data.writeStrongBinder(resultTo);
           data.writeString(resultWho);
           data.writeInt(requestCode);
           data.writeInt(startFlags);
           if (profilerInfo != null) {
               data.writeInt(1);
               profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
           } else {
               data.writeInt(0);
           }
           if (options != null) {
               data.writeInt(1);
               options.writeToParcel(data, 0);
           } else {
               data.writeInt(0);
           }
           //调用号为START_ACTIVITY_TRANSACTION
           mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
           reply.readException();
           int result = reply.readInt();
           reply.recycle();
           data.recycle();
           return result;
       }
       ...
    }
    

    AMP经过binder IPC,进入ActivityManagerNative(简称AMN)。接下来程序进入了system_servr进程,开始继续执行。

    可以看到,AMP 里面将客户端的请求通过 mRemote.transact 进行转发,mRemote 对象正是 Binder 驱动返回来的 Binder Proxy 对象,通过 Binder Proxy,Binder 驱动最终将调用处于 Binder Server 端 AMN 中的 onTransact 方法:

    AMN.onTransact

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
       switch (code) {
       case START_ACTIVITY_TRANSACTION:
       {
         data.enforceInterface(IActivityManager.descriptor);
         IBinder b = data.readStrongBinder();
         IApplicationThread app = ApplicationThreadNative.asInterface(b);
         String callingPackage = data.readString();
         Intent intent = Intent.CREATOR.createFromParcel(data);
         String resolvedType = data.readString();
         IBinder resultTo = data.readStrongBinder();
         String resultWho = data.readString();
         int requestCode = data.readInt();
         int startFlags = data.readInt();
         ProfilerInfo profilerInfo = data.readInt() != 0
                 ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
         Bundle options = data.readInt() != 0
                 ? Bundle.CREATOR.createFromParcel(data) : null;
         //又出现了startActivity方法,进去看看
         int result = startActivity(app, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
         reply.writeNoException();
         reply.writeInt(result);
         return true;
       }
       ...
       }    }
    

    AMN 是一个抽象类,它的 startActivity 为抽象方法,具体的实现在AMS里.

    小结:

    从 Launcher App 到 AMS 的调用过程中使用了 Binder IPC 机制,调用方 Launcher App 相当于 AIDL 过程中的 Activity 所在的 App,充当 Clinent 的角色;AMS 相当于远程 Service 的角色,充当 Server 端角色,他们的调用过程总体上都是一样的。

    从 Launcher App 到 AMS 的时序图如下:

    AMS——zygote调用过程分析

    AMS.startActivity

    
     public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }
    
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        //mActivityStarter的数据类型为ActivityStarter
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }
    

    ActivityStarter.startActivityMayWait

    当程序运行到这里时, AS.startActivityMayWait的主要参数取值如下:

    • caller = ApplicationThreadProxy, 用于跟调用者进程ApplicationThread进行通信的binder代理类.
    • callingPackage = ContextImpl.getBasePackageName(),获取调用者Activity所在包名
    • intent: 这是启动Activity时传递过来的参数
    • resolvedType = intent.resolveTypeIfNeeded
    • resultTo = Activity.mToken, 其中Activity是指调用者所在Activity, mToken对象保存自己所处的ActivityRecord信息
    • resultWho = Activity.mEmbeddedID, 其中Activity是指调用者所在Activity
    • userId = AMS.handleIncomingUser, 当调用者userId跟当前处于同一个userId,则直接返回该userId;当不相等时则根据调用者userId来决定是否需要将callingUserId转换为mCurrentUserId

    在上源码:

    final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration config, Bundle options, boolean ignoreTargetSecurity, int userId, IActivityContainer iContainer, TaskRecord inTask) {
        ...
        boolean componentSpecified = intent.getComponent() != null;
        //创建新的Intent对象,即便intent被修改也不受影响
        intent = new Intent(intent);
    
        //收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity 
        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
    
        ActivityContainer container = (ActivityContainer)iContainer;
        synchronized (mService) {
            ···
            //调用startActivityLocked方法
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);
    
            Binder.restoreCallingIdentity(origId);
            ···
            return res;
        }
    }
    

    该过程主要功能:通过resolveActivity来获取ActivityInfo信息, 然后再进入ActivityStarter.startActivityLocked(),之后会依次调用(具体源码就不贴了,走个大致流程):

    • ActivityStarter.doPendingActivityLaunchesLocked()
    • ActivityStarter.startActivityUnchecked()
    • ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()
    • ActivityStack.resumeTopActivityUncheckedLocked()
    • ActivityStack.resumeTopActivityInnerLocked()
    • ActivityStackSupervisor.startSpecificActivityLocked()

    这里我们需要看看最后一个流程,ActivityStackSupervisor.startSpecificActivityLocked()里做了什么:

    void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // 当前 Activity 附属的 Application
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        r.task.stack.setLaunchTime(r);
        // 如果 Application 已经运行
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }
        // 启动新进程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
    

    首先,在方法中获取了当前 Activity 附属的 Application,如果已经在运行了,说明这个 App 是已经被启动过了的,这时候调用 realStartActivityLocked 方法就可以进入下一步的流程了,同一个 App 中不同 Activity 的相互启动就是走的这个流程。当 Application 没有运行的时候,就需要调用 AMS 的 startProcessLocked 方法启动一个进程去承载它然后完成后续的工作,顺便铺垫一下,当新进程被启动完成后还会调用回到这个方法,查看 AMS 的 startProcessLocked方法

    ActivityManagerService.startProcessLocked

    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 */);
    }
    

    这里调用了AMS的另一个startProcessLocked重载方法,看源码:

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs){
        ...
        try {
            ...
            boolean isActivityProcess = (entryPoint == null);            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                        app.processName);
                checkTime(startTime, "startProcess: asking zygote to start proc");
            // 调用 Process 的 start 方法
            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);
            ...
        } catch (RuntimeException e) {
            ...
        }
    }
    

    AMS有四个startProcessLocked重载方法,最后这里调用了Process.start方法,其中这里有个entryPoint字段,这个参数是什么呢,这就是一个ActivityThread。这个参数传进来的目的,我们先不说,后面再谈。

    Process.start

    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
          ...
        }
    }
    

    start函数中只调用了startViaZygote方法:

    private static ProcessStartResult startViaZygote(final String processClass,
                                      final String niceName,
                                      final int uid, final int gid,
                                      final int[] gids,
                                      int debugFlags, int mountExternal,
                                      int targetSdkVersion,
                                      String seInfo,
                                      String abi,
                                      String instructionSet,
                                      String appDataDir,
                                      String[] extraArgs)
                                      throws ZygoteStartFailedEx {
            synchronized(Process.class) {
            /**
            * 1
            */
                ArrayList<String> argsForZygote = new ArrayList<String>();
                argsForZygote.add("--runtime-args");
                argsForZygote.add("--setuid=" + uid);
                argsForZygote.add("--setgid=" + gid);
              ...
                if (gids != null && gids.length > 0) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("--setgroups=");
    
                    int sz = gids.length;
                    for (int i = 0; i < sz; i++) {
                        if (i != 0) {
                            sb.append(',');
                        }
                        sb.append(gids[i]);
                    }
    
                    argsForZygote.add(sb.toString());
                }
             ...
                argsForZygote.add(processClass);
                if (extraArgs != null) {
                    for (String arg : extraArgs) {
                        argsForZygote.add(arg);
                    }
                }
                return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
            }
        }
    

    在注释1处创建了字符串列表argsForZygote ,并将启动应用进程的启动参数保存在argsForZygote中,函数的最后会调用zygoteSendArgsAndGetResult函数,需要注意的是,zygoteSendArgsAndGetResult函数中第一个参数中调用了openZygoteSocketIfNeeded函数,而第二个参数是保存应用进程的启动参数的argsForZygote。zygoteSendArgsAndGetResult函数如下

    private static ProcessStartResult zygoteSendArgsAndGetResult(
                ZygoteState zygoteState, ArrayList<String> args)
                throws ZygoteStartFailedEx {
            try {
                final BufferedWriter writer = zygoteState.writer;
                final DataInputStream inputStream = zygoteState.inputStream;
                writer.write(Integer.toString(args.size()));
                writer.newLine();
                int sz = args.size();
                for (int i = 0; i < sz; i++) {
                    String arg = args.get(i);
                    if (arg.indexOf('\n') >= 0) {
                        throw new ZygoteStartFailedEx(
                                "embedded newlines not allowed");
                    }
                    writer.write(arg);
                    writer.newLine();
                }
                writer.flush();
                // Should there be a timeout on this?
                ProcessStartResult result = new ProcessStartResult();
                result.pid = inputStream.readInt();
                if (result.pid < 0) {
                    throw new ZygoteStartFailedEx("fork() failed");
                }
                result.usingWrapper = inputStream.readBoolean();
                return result;
            } catch (IOException ex) {
                zygoteState.close();
                throw new ZygoteStartFailedEx(ex);
            }
        }
    

    zygoteSendArgsAndGetResult函数主要做的就是将传入的应用进程的启动参数argsForZygote,写入到ZygoteState中,结合上文我们知道ZygoteState其实是由openZygoteSocketIfNeeded函数返回的,那么我们接着来看openZygoteSocketIfNeeded函数,代码如下所示

    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);//1
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }
        if (primaryZygoteState.matches(abi)) {//2
            return primaryZygoteState;
        }
        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);//3
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }
    
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }
    
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    
    • 注释1处会调用ZygoteState的connect函数与名称为ZYGOTE_SOCKET的Socket建立连接,这里ZYGOTE_SOCKET的值为“zygote”,这是因为Zygote进程启动过程时,在Zygote的main函数中会创建name为“zygote”的Server端Socket。
    • 注释2处如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会在注释3处连接name为“zygote_secondary”的Socket。这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。

    Zygote——ActivityThread

    Socket进行连接成功并匹配abi后会返回ZygoteState类型对象,我们在分析zygoteSendArgsAndGetResult函数中讲过,会将应用进程的启动参数argsForZygote写入到ZygoteState中,这样Zygote进程就会收到一个创建新的应用程序进程的请求,我们回到ZygoteInit的main函数,如下所示。

    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    public static void main(String argv[]) {
           ...
            try {
             ...       
                //注册Zygote用的Socket
                registerZygoteSocket(socketName);//1
               ...
               //预加载类和资源
               preload();//2
               ...
                if (startSystemServer) {
                //启动SystemServer进程
                    startSystemServer(abiList, socketName);//3
                }
                Log.i(TAG, "Accepting command socket connections");
                //等待客户端请求
                runSelectLoop(abiList);//4
                closeServerSocket();
            } catch (MethodAndArgsCaller caller) {
                caller.run();
            } catch (RuntimeException ex) {
                Log.e(TAG, "Zygote died with exception", ex);
                closeServerSocket();
                throw ex;
            }
        }
    
    • 注释1处通过registerZygoteSocket函数来创建一个Server端的Socket,这个name为”zygote”的Socket用来等待ActivityManagerService来请求Zygote来创建新的应用程序进程
    • 注释2处用来预加载类和资源。
    • 注释3处用来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。
    • 注释4处调用runSelectLoop函数来等待ActivityManagerService的请求,我们就来查看runSelectLoop:

    frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
            ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
            ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//2
            fds.add(sServerSocket.getFileDescriptor());
            peers.add(null);
            while (true) {
            ...
                for (int i = pollFds.length - 1; i >= 0; --i) {
                    if ((pollFds[i].revents & POLLIN) == 0) {
                        continue;
                    }
                    if (i == 0) {
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        fds.add(newPeer.getFileDesciptor());
                    } else {
                        boolean done = peers.get(i).runOnce();//1
                        if (done) {
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                }
            }
        }
    

    当有ActivityManagerService的请求数据到来时会调用注释1处的代码,结合注释2处的代码,我们得知注释1处的代码其实是调用ZygoteConnection的runOnce函数来处理请求的数据:

    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
            String args[];
            Arguments parsedArgs = null;
            FileDescriptor[] descriptors;
            try {
                args = readArgumentList();//1
                descriptors = mSocket.getAncillaryFileDescriptors();
            } catch (IOException ex) {
                Log.w(TAG, "IOException on command socket " + ex.getMessage());
                closeSocket();
                return true;
            }
    ...
            try {
                parsedArgs = new Arguments(args);//2
            ...
            /**
            * 3 
            */
                pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                        parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                        parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                        parsedArgs.appDataDir);
            } catch (ErrnoException ex) {
              ....
            }
           try {
                if (pid == 0) {
                    // in child
                    IoUtils.closeQuietly(serverPipeFd);
                    serverPipeFd = null;
                    handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                    return true;
                } else {
                    // in parent...pid of < 0 means failure
                    IoUtils.closeQuietly(childPipeFd);
                    childPipeFd = null;
                    return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
                }
            } finally {
                IoUtils.closeQuietly(childPipeFd);
                IoUtils.closeQuietly(serverPipeFd);
            }
        }
    

    在注释1处调用readArgumentList函数来获取应用程序进程的启动参数,并在注释2处将readArgumentList函数返回的字符串封装到Arguments对象parsedArgs中。注释3处调用Zygote的forkAndSpecialize函数来创建应用程序进程,参数为parsedArgs中存储的应用进程启动参数,返回值为pid。forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程的,如果pid等于0,则说明是在新创建的子进程中执行的,就会调用handleChildProc函数来启动这个子进程也就是应用程序进程,如下所示

    frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

    private void handleChildProc(Arguments parsedArgs,
                FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
                throws ZygoteInit.MethodAndArgsCaller {
          ...
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        }
    

    handleChildProc函数中调用了RuntimeInit的zygoteInit函数,如下所示。

    frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
                throws ZygoteInit.MethodAndArgsCaller {
            if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
            redirectLogStreams();
            commonInit();
            nativeZygoteInit();//1
            applicationInit(targetSdkVersion, argv, classLoader);//2
        }
    

    注释1处会在新创建的应用程序进程中创建Binder线程池,在注释2处调用了applicationInit函数:

    frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
                throws ZygoteInit.MethodAndArgsCaller {
     ...
            final Arguments args;
            try {
                args = new Arguments(argv);
            } catch (IllegalArgumentException ex) {
                Slog.e(TAG, ex.getMessage());       
                return;
            }
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            invokeStaticMain(args.startClass, args.startArgs, classLoader);//1
        }
    

    在applicationInit中会在注释1处调用invokeStaticMain函数,需要注意的是第一个参数args.startClass,这里指的就是前文提到的参数:android.app.ActivityThread。接下来我们查看invokeStaticMain函数。

    frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;
        try {
            cl = Class.forName(className, true, classLoader);//1
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });//2
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        }
        ...
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);//3
    }
    

    可以看到注释1处通过反射来获得android.app.ActivityThread类,接下来在注释2处来获得ActivityThread的main函数,并将main函数传入到注释3处的ZygoteInit中的MethodAndArgsCaller类的构造函数中,MethodAndArgsCaller类内部会通过反射调用ActivityThread的main函数,前文ZygoteInit.main中会捕获该异常,调用caller.run方法,这样应用程序进程就创建完成了,使用抛出捕获异常来调用,主要是为了把当前线程堆栈的信息给置空。

    ActivityThread.main

    从 ActivityThread 的main方法开始,应用进入 java 层,应用在main里面的关键代码:

    public static void main(String[] args) {
            ... ...
            Looper.prepareMainLooper();
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
            ... ...
            Looper.loop();
        }
    

    主要的三件事:

    • 调用Looper.prepareMainLooper 创建mainLooper并赋值给Loop (这个looper的MessageQueue不能quit)静态变量 sMainLooper ,这样应用可以在任何地方拿到主线程的Looper
    • 创建ActivityThread实例,并调用attach,这两步很关键,首先,ActivityThread对象创建时,会创建ResourcesManager的单例对象,还会创建 ApplicationThread 对象作为匿名Binder服务端用以跟system_server进程通信,在thread.attach(false) 中通过AMP把 这个对象注册到AMS:

    看看thread.attach方法做了什么:

     @UnsupportedAppUsage
        private void attach(boolean system, long startSeq) {
            sCurrentActivityThread = this;
            mSystemThread = system;
            if (!system) {
                ···
                RuntimeInit.setApplicationObject(mAppThread.asBinder());
                final IActivityManager mgr = ActivityManager.getService();
                try {
                    mgr.attachApplication(mAppThread, startSeq);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }else{
            ···
            }
        }
    

    AMS 对各应用组件的生命周期管理就是通过这个对象实现的,AMS会通过这个ApplicationThread 对象远程调用应用进程的方法从而实现管理。
    另外在attach 方法里ActivityThread对象会把自己赋值给静态变量sCurrentActivityThread,在应用开发中可以通过反射ActivityThread 直接拿到这个静态变量对象或反射后调用静态方法 currentActivityThread()拿到应用的ActivityThread 对象,从而可以拿到其成员变量mAppThread,mInstrumentation,插件化方案可能需要hook这两个对象

    • 主线程启动loop,进入循环,等待其他线程往消息队列里发消息

    站在巨人们的肩膀上

    Android应用进程启动过程

    慕课网应用启动流程

    应用启动流程

    相关文章

      网友评论

        本文标题:Android App启动流程浅谈(上)——Android 9.

        本文链接:https://www.haomeiwen.com/subject/yjshqctx.html