美文网首页
Android源码分析之App启动流程(二)

Android源码分析之App启动流程(二)

作者: 大大纸飞机 | 来源:发表于2018-07-11 10:46 被阅读111次

    续前节,我们已经知道,Zygote孵化完进程之后会invoke ActivityThread#main方法,现在继续看剩下的部分。该方法代码如下:

    /frameworks/base/core/java/android/app/ActivityThread.java

    public static void main(String[] args) {
        ...
    
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        ...
        Looper.loop();
    
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    

    可以看到这里首先开启了Looper消息循环,这部分知识我们以后再来分析。下面主要看下ActivityThread#attach(boolean)方法,代码如下:

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ...
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ...
        } else {
            ...
        }
    
        ...
    }
    

    因为不是系统APP,所以只需要看if里的代码就好了。之前已经分析过,ActivityManagerNative#getDefault()方法获取到的是ActivityManagerProxy实例,然后这个实例通过BinderProxyActivityManagerService进行通信。接下来代码如下:

    /frameworks/base/core/java/android/app/ActivityManagerNative.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);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
    

    和之前的做法非常一致,接下来会执行到ActivityManagerService#onTransact方法,而相关代码在父类ActivityManagerNative中,代码如下:

    case ATTACH_APPLICATION_TRANSACTION: {
        data.enforceInterface(IActivityManager.descriptor);
        IApplicationThread app = ApplicationThreadNative.asInterface(
                data.readStrongBinder());
        if (app != null) {
            attachApplication(app);
        }
        reply.writeNoException();
        return true;
    }
    

    这里看到IApplicationThread实例是通过ApplicationThreadNative#asInterface获取的,根据先前的经验,这里应该是一个ApplicationThreadProxy实例,相关代码如下:

    /frameworks/base/core/java/android/app/ApplicationThreadNative.java

    static public IApplicationThread asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IApplicationThread in =
            (IApplicationThread)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
    
        return new ApplicationThreadProxy(obj);
    }
    

    接下来就可以确认,ActivityManagerService#attachApplication(IApplicationThread)方法中的IApplicationThread实例是ApplicationThreadProxy,代码如下:

    /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ...
        try {
            ...
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
            updateLruProcessLocked(app, false, null);
            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
        } catch (Exception e) {
            ...
        }
    
        ...
        
        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
        ...
        return true;
    }
    

    然后看下这里ApplicationThreadProxy#bindApplication方法,代码如下:

    /frameworks/base/core/java/android/app/ApplicationThreadNative.java

    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 {
        ...
        mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    

    这里的思路和ActivityManagerNative十分一致,通过ApplicationThreadProxyBinderProxy来完成ApplicationThreadActivityManagerService通信,然后由ApplicationThreadNative处理返回的结果,并调用ApplicationThread的对应方法。接下来看下ApplicationThread#bindApplication方法:

    /frameworks/base/core/java/android/app/ActivityThread.java

    public 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) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }
    
        setCoreSettings(coreSettings);
    
        AppBindData data = new 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;
        sendMessage(H.BIND_APPLICATION, data);
    }
    

    这里把一些需要设置的属性,通过一个叫AppBindData的方式包装起来,然后通过Handler方式,发送给了一个叫HHandler实例,这个实例在ActivityThread中,我们看下它在handleMessage中对BIND_APPLICATION这个消息的处理:

    case BIND_APPLICATION:
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
        AppBindData data = (AppBindData)msg.obj;
        handleBindApplication(data);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        break;
    
    private void handleBindApplication(AppBindData data) {
        ...
        // Continue loading instrumentation.
        if (ii != null) {
            ...
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
    
            if (mProfiler.profileFile != null && !ii.handleProfiling
                    && mProfiler.profileFd == null) {
                mProfiler.handlingProfiling = true;
                final File file = new File(mProfiler.profileFile);
                file.getParentFile().mkdirs();
                Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
            }
        } else {
            mInstrumentation = new Instrumentation();
        }
    
        ...
    
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
    
            ...
    
            // Do this after providers, since instrumentation tests generally start their
            // test thread at this point, and we don't want that racing.
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                ...
            }
    
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                ...
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }
    

    handleBindApplication做了非常多的工作,APP的名称、资源、屏幕相关等操作都在这里进行了处理,但这不是我们今天关注的重点,我们主要看最下边的try-catch,这里首先创建了一个Application实例,然后调用了mInstrumentation.onCreatemInstrumentation.callApplicationOnCreate,这两个方法一个是空的,一个调用了Application#onCreate(),没有做更多的事情,这里暂时不关注它。这里这个Application实例是通过LoadedApk#makeApplication完成的,代码如下:

    /frameworks/base/core/java/android/app/LoadedApk.java

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
    
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    
        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")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
    
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                ...
            }
        }
    
        ...
        return app;
    }
    

    可以看到这个Application是通过Instrumentation#newApplication方法完成的,代码如下:

    /frameworks/base/core/java/android/app/Instrumentation.java

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }
    
    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }
    

    这里看到Application是通过ClassLoader创建出来的,随后调用了它的attach方法,该方法如下:

    /frameworks/base/core/java/android/app/Application.java

    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
    

    至此,Application就创建完毕了,并且Application#onCreate()方法也执行完毕了。接下来就是启动Activity的过程,在之前分析ActivityManagerService#attachApplicationLocked方法中,执行完毕thread.bindApplication之后又执行了mStackSupervisor.attachApplicationLocked(app),也就是创建完Application之后,启动需要运行的Activity,相应的代码如下:

    /frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFocusedStack(stack)) {
                    continue;
                }
                ActivityRecord hr = stack.topRunningActivityLocked();
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                    + hr.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        }
        return didSomething;
    }
    

    因为是首次运行,所以会执行到if (realStartActivityLocked(hr, app, true, true))代码块,如下所示:

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
        ...
        final ActivityStack stack = task.stack;
        try {
            ...
            app.forceProcessStateUpTo(mService.mTopProcessState);
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
    
            ...
        } catch (RemoteException e) {
            ...
        }
        ...
        return true;
    }
    

    现在,终于开始加载Activity了,代码如下:

    /frameworks/base/core/java/android/app/ActivityThread.java

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
    
        updateProcessState(procState, false);
    
        ActivityClientRecord r = new ActivityClientRecord();
    
        ...
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
    

    可以看到这里依然是通过H来交互的,代码如下:

    case LAUNCH_ACTIVITY: {
        ...
        
        handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    } break;
    
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ...
    
        Activity a = performLaunchActivity(r, customIntent);
    
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ...
        } else {
            ...
        }
    }
    

    这里首先通过performLaunchActivity获取到需要加载的Activity,然后调用handleResumeActivity方法。我们先看前者,代码如下:

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
    
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ...
        } catch (Exception e) {
            ...
        }
    
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ...
    
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                ...
                
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
                ...
                if (theme != 0) {
                    activity.setTheme(theme);
                }
    
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    ...
                }
            }
            r.paused = true;
    
            mActivities.put(r.token, r);
    
        } catch (SuperNotCalledException e) {
            throw e;
    
        } catch (Exception e) {
            ...
        }
    
        return activity;
    }
    

    这里首先通过Instrumentation#newActivity方法创建了一个Activity,然后调用了它的一些生命周期方法,包括它的ThemeWindow等都是在这时候设置的,还是先看下创建的过程,代码如下:

    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
    

    和创建Application一样,也是通过ClassLoader完成的,Activity创建完成后接着调用了Activity#attach方法,在最开始时候提到过这个方法,并说它需要的ActivityThread是通过这个方法传入的,这里终于找到调用的地方了。接下来依次调用了ActivityonCreateonStartonRestoreInstanceStateonPostCreate方法,最后回到handleLaunchActivity,调用了handleResumeActivity。接下来的代码就涉及到了Activity加载View了,我们之后再分析。

    上一篇:Android源码分析之App启动流程(一)

    下一篇:Android源码分析之Activity启动与View绘制流程

    相关文章

      网友评论

          本文标题:Android源码分析之App启动流程(二)

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