安卓App啟動(dòng)流程源碼分析

源碼在26之后貌似變了一些東西,自己學(xué)習(xí),自己記錄一下,加深一下理解

首先當(dāng)你在laucher點(diǎn)擊一個(gè)應(yīng)用圖標(biāo)的就會(huì)去啟動(dòng)一個(gè)app
一個(gè)app啟動(dòng)的入口就是這個(gè)ActivityThread,實(shí)際就是點(diǎn)擊圖標(biāo)之后啟動(dòng)一個(gè)線程來搞事情,這個(gè)線程就是主線程
ActivityThread方法有一個(gè)main方法,就是程序的入口了,看一下這個(gè)方法都搞了一些什么事情

 public static void main(String[] args) {
        ....
       //這一堆是初始化了系統(tǒng)目錄等一些東西,從Environment類就可以看出來主要干什么
        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
         ...
        //初始化化主線程的Looper
        Looper.prepareMainLooper();
   
        //綁定線程
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        //主線程處理消息的Handler
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        //開啟Looper進(jìn)行無線循環(huán)處理
        Looper.loop();
        ...
    }

其實(shí)啟動(dòng)很簡單,就是在主線程初始化一個(gè)Looper,然后創(chuàng)建一系列的消息指令放到消息隊(duì)列,開啟looper循環(huán)進(jìn)行處理,復(fù)雜的地方全在 thread.attach這個(gè)步驟里.
先不去看其他的,先看一下主線程的這個(gè)Looper是怎們創(chuàng)建的,我們知道在平時(shí)使用Handler的時(shí)候不需要?jiǎng)?chuàng)建Looper(UI線程使用),其實(shí)就是用為在這個(gè)地方進(jìn)行了初始化,點(diǎn)擊方法prepareMainLooper我們查看代碼發(fā)現(xiàn)這里首先調(diào)用了prepare方法,然后直接調(diào)用myLooper方法為主線程Looper進(jìn)行了賦值

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

這倆個(gè)方法做了什么呢
prepare方法:
發(fā)現(xiàn)一個(gè)東西ThreadLocal,ThreadLocal是一個(gè)線程安全的包裝機(jī)制

  private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper中保存著一個(gè)ThreadLocal,首先通過ThreadLocal.get去獲取looper,如果獲取到了,那么久說明不對(duì)頭,拋出異常,一個(gè)線程只能有一個(gè)Looper的,如果沒有,那么就為ThreadLocal設(shè)置一個(gè)Looper進(jìn)去

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

看下Looper的構(gòu)造函數(shù),掙了一個(gè)消息隊(duì)列,然后保存當(dāng)前這個(gè)調(diào)用他的線程,很簡單,

 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

然后就是看下mylooper這個(gè)方法了

 public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

再看get方法,這個(gè)threadLocal存放著一個(gè)map來保存looper,調(diào)用get的時(shí)候回根據(jù)線程來獲取相應(yīng)的looper,所以現(xiàn)在可以知道了,主線程的Looper以及平時(shí)可能會(huì)在子線程中調(diào)用的looper都被存放到這個(gè)map中了,現(xiàn)在可以看明白myLooper方法其實(shí)就是去獲取一下當(dāng)前線程的looper

  public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

到這里L(fēng)ooper的相關(guān)創(chuàng)建就完成了.

然后就是attach方法,這里面做了大部分主要內(nèi)容

 private void attach(boolean system) {
            ...
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ...
         }

上面的代碼大體可以看出來是做了一個(gè)綁定applaction的操作,在api25之前這里獲取到的是一個(gè)ActivityManager的代理來處理這個(gè)問題的,25之后變成了使用AIDL來做處理這個(gè)問題,看代碼

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

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

ServiceManager.getService方法會(huì)經(jīng)過ServiceManagerNative類的一個(gè)內(nèi)部類代理去獲取AMS,最終獲取到這個(gè)類ActivityManagerService
下一步會(huì)調(diào)用mgr.attachApplication(mAppThread)這個(gè)東西,去AMS中找一下這個(gè)方法看看有沒有

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
--------------------------------------------------------------------------------
            attachApplicationLocked(thread, callingPid);
------------------------------------------------------------------------------
            Binder.restoreCallingIdentity(origId);
        }
    }

找到如上圖一個(gè)方法,獲取了一下進(jìn)程,清楚了一下進(jìn)程的調(diào)用標(biāo)記?好像是這樣子額,
然后最主要的是中間代碼,看看代碼
代碼太長了這個(gè)方法,幾百行代碼,掐頭去尾,留下中間比較重要的.

 private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
...
if (app.instr != null) {
                thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial);
            } else {
                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial);
            }
...
}

中間著部分代碼的前半段貌似做了一些進(jìn)程的相關(guān)操作,后半段做了一些安全的驗(yàn)證,檢查下這個(gè)進(jìn)程中是否還遺留一些activity啊,廣播啊這類的,這些沒有深看,主要看中間代碼
IApplicationThread 是個(gè)什么,發(fā)現(xiàn)這個(gè)是個(gè)ActivityThread的內(nèi)部類,并且作為一個(gè)final常量被使用,在這個(gè)方法中調(diào)用了IApplicationThread的bindApplication方法,看方法名應(yīng)該是個(gè)重要操作,綁定Applaction,我們看一下這個(gè)方法做了什么
咋一看,哎呀呀好多參數(shù),心理慌得一筆,細(xì)看其實(shí)就是一個(gè)賦值,直到最后一行代碼,發(fā)現(xiàn)了么,這個(gè)里很明顯發(fā)送了一個(gè)消息,去綁定applaction,并把相關(guān)的包信息啊什么的傳過去,反正經(jīng)過饒了AMS一圈還是回到了activityThread來處理...


        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 services, Bundle coreSettings,
                String buildSerial) {

            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;
            data.buildSerial = buildSerial;
            sendMessage(H.BIND_APPLICATION, data);
        }

然后我們找一下handler是怎們處理的,這個(gè)方法也比較長,大部分代碼為進(jìn)行一些啟動(dòng)app前的配置操作,比如配置時(shí)區(qū)啊等等一些根據(jù)data的內(nèi)容進(jìn)行的,所以我們刪除一些不重要的,慢慢看,留下幾個(gè)看起來有用的代碼

private void handleBindApplication(AppBindData data) {
  // 將UI線程注冊(cè)為敏感線程
        VMRuntime.registerSensitiveThread();
        if (data.trackAllocation) {
            DdmVmInternal.enableRecentAllocations(true);
        }
    ...
    mInstrumentation = (Instrumentation)
        cl.loadClass(data.instrumentationName.getClassName())
        .newInstance();
    //通過反射初始化一個(gè)Instrumentation儀表。
    ...
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    //通過LoadedApp命令創(chuàng)建Application實(shí)例
    mInitialApplication = app;
    ...
    mInstrumentation.callApplicationOnCreate(app);
    //讓儀器調(diào)用Application的onCreate()方法
    ...
}

我們發(fā)現(xiàn)在一頓猛如虎的操作者之后有個(gè)名字叫mInstrumentation的少年調(diào)用了applaction的onCreat方法,只是簡單的調(diào)用了一下 app.onCreate(),為什么不直接調(diào)用呢?

  public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

我們先看mInstrumentation這個(gè)是什么?
Android instrumentation是Android系統(tǒng)里面的一套控制方法或者”鉤子“。這些鉤子可以在正常的生命周期(正常是由操作系統(tǒng)控制的)之外控制Android控件的運(yùn)行,其實(shí)指的就是Instrumentation類提供的各種流程控制方法.
然后我們繼續(xù)發(fā)現(xiàn)callApplicationOnCreate要一個(gè)app參數(shù),這個(gè)app是從哪里來的?繼續(xù)像上看代碼發(fā)現(xiàn)app產(chǎn)自這么一個(gè)方法makeApplication()
看一下這個(gè)方法干了什么事情

 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);
...........
}

發(fā)現(xiàn)是由一個(gè)叫LoadedApk的類去執(zhí)行的,這個(gè)類是維護(hù)這本地已經(jīng)加載的apk,不管為啥要用它去創(chuàng)建applaction,看這個(gè)代碼的意思就是如果有這個(gè)app就直接返回,沒有就用反射創(chuàng)建一個(gè),創(chuàng)建過程又交給了儀表盤mInstrumentation

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

簡單的反射創(chuàng)建了applaction,整個(gè)過程操作猶如猛虎下山,勢(shì)不可擋啊.

然后就是Application初始化完畢之后會(huì)給主線程的handler發(fā)送一個(gè)啟動(dòng)activity的消息,最終會(huì)走這么一個(gè)方法

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
      創(chuàng)建一個(gè)activty
       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);
}

首先調(diào)用performLaunchActivity方法創(chuàng)建一個(gè)activity,然后就可以handleResumeActivity,就是可以走onResume方法了

具體看下performLaunchActivity方法

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
.....
 activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);

.....
 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
.....
  activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
....
  if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
....
}

發(fā)現(xiàn)任然是由儀表盤去創(chuàng)建的這個(gè)activity,然后做一個(gè)attach操作綁定界面,然后就是一些流程控制的操作,callActivityOnCreate,就可以執(zhí)行activity的oncreat方法了...最后返回一個(gè)activity.

mInstrumentation.newActivity來創(chuàng)建activity其實(shí)就是一個(gè)反射區(qū)創(chuàng)建,很簡單
基本走到handleResumeActivity方法的時(shí)候就沒什么了,一個(gè)app的啟動(dòng)并展示第一個(gè)界面的過程就完成了,總體就是這么一個(gè)流程,但是其中還有無數(shù)細(xì)節(jié)待我們慢慢研究啊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容