Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Small插件化框架--啟動插件Activity源碼解析(下)

Android Small插件化框架--啟動插件Activity源碼解析(下)

編輯:關於Android編程

AMS對startActivity請求處理及返回過程

根據上一章的分析了解了調用startActivity(),終於把數據和要開啟Activity的請求發送到了AMS了,接下來分析在AMS中的處理過程和重新回到app進程。

1、在AMS中處理的過程

AMS中處理startActivity的過程比較復雜,主要涉及了ActivityManagerService、ActivityStackSupervisor、ActivityStack、PackageManagerService、WindowManagerService等幾個類。

在ActivityManagerService中,startActivity先是調用了startActivityAsUser(注意,第一個參數caller就是app在服務端的代理ApplicationThreadProxy,它是一個Binder對象,實現了IApplicationThread。):

    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

然後在startActivityAsUser中調用了ActivityStackSupervisor的startActivityMayWait。

    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        ......
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);
    }

轉到ActivityStackSupervisor中後,又在它和ActivityStack之間來回調用了許多次,主要是進行棧和Task的管理、解析Activity的信息,准備窗口的切換之類的工作,最後回到了ActivityStackSupervisor中,調用realStartActivityLocked函數。

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
            ......
            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);
    }

在realStartActivityLocked函數中,app是ProcessRecord類型,app.thread是IApplicationThread類型,也就是從客戶端的代理ApplicationThreadProxy,在這兒調用了它的scheduleLaunchActivity方法,接下來就是回到app的進程空間裡的過程。

2、AMS回到app進程

再回顧一下AMS和app之間交互原理圖:

\

ActivityThread的類圖結構:

\

ApplicationThreadProxy中scheduleLaunchActivity方法:

    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 pendingResults, List pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
        ......
        mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }

在該方法中調用IBinder的transact發出命令,然後由ApplicationThread的代理ApplicationThreadNative的onTransact來處理:

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
            ......
            case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
        {
            ......
            scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
                    referrer, voiceInteractor, procState, state, persistentState, ri, pi,
                    notResumed, isForward, profilerInfo);
            return true;
        }
}

ApplicationThreadNative的onTransact函數會調用scheduleLaunchActivity,其具體實現在ApplicationThread中:

    private class ApplicationThread extends ApplicationThreadNative {
        ......
        @Override
        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 pendingResults, List pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
}

ApplicationThread是ActivityThread裡的一個內部類,它的scheduleLaunchActivity的實現就是發一個LAUNCH_ACTIVITY類型的message到ActivityThread中的一個handler上。

    private class H extends Handler {
            public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
        ......
        }
    }

H類繼承自Handler也是Activity Thread的內部類,重寫了handleMessage(Message msg)方法。根據標識LAUNCH_ACTIVITY調用了handleLaunchActivity()方法,handleLaunchActivity裡調用了performLaunchActivity:

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ......  
        Activity a = performLaunchActivity(r, customIntent);
    }

performLaunchActivity中又用到了Instrumentation類,調它的newActivity函數構造出activity對象。newActivity函數很簡單,直接用classLoader加載了Activity類,然後用反射調它的構造函數newInstance出activity實例:

    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);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
    }
        public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

然後再回到performLaunchActivity中,在通過newActivity得到activity的實例後,接下來就該調用它的生命周期函數onCreate了,照舊還是通過Instrumentation來完成,調用它的callActivityOnCreate函數。

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }

在callActivityOnCreate裡會調用Activity的performCreate函數,它裡面調用的就是我們熟悉的onCreate了。

    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle, persistentState);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

app到AMS過程時序圖:

\

 
總結:到此為止,startActivity的整個流程就結束了,從整個完整流程可以看出,Instrumentation這個類是startActivity整個過程中的必經之路,無論是從app到AMS,還是從AMS回到app都會經過它,所以它就是Hook對象。並且它是ActivityThread裡的一個成員mInstrumentation,所以我們在客戶端進程中可以通過反射拿到ActivityThread對象,也可以拿到mInstrumentation。

在早期版本中,作者hook的是newActivity,最新版本將其改為對handler.callback進行hook。為什麼?

通過請教作者,他給我的答復是:“提前hook時機,可以減少“善後”工作,handler是跑到App進程最開始的地方,到了newActivity實際上有很多事已經被做掉了,需要再通過反射來重置一些參數,比如Resources,這意味著一件事你實際上做了兩次。所以越早處理越好。”

Small中對StartActivity的返回處理解析

根據以上原理分析我們知道ActivityThread中的內部類H繼承自handler處理主線程消息對列(MessageQueue)中的Message。因為Android的UI操作是由handler機制進行的,所以在Activity的創建需要通過H類處理。Small框架在對AMS到app的過程進行Hook的就是H類。具體在ApkBundleLauncher實現如下:

     public void setUp(Context context) {
        ......
        // 反射獲取ActivityThread類中mH成員變量
        field = activityThreadClass.getDeclaredField("mH");
        field.setAccessible(true);
        //獲得activityThread對象中mH成員變量的屬性值
        Handler ah = (Handler) field.get(thread);

        //反射獲取Handler類中mCallback成員變量
        field = Handler.class.getDeclaredField("mCallback");
        field.setAccessible(true);
        //向ah對象中賦值為ActivityThreadHandlerCallback()
        //此刻的field是mCallback成員變量,下面就將ActivityThreadHandlerCallback的實例賦給mCallback變量
        field.set(ah, new ActivityThreadHandlerCallback());

    }

由以上可知Small主要改變了H類中mCallback成員變量的值。
為什麼要這樣做呢?
根據handler源碼解析可知,Handler內部是通過執行dispatchMessage方法以實現對Message的處理的,Handler的dispatchMessage的源碼如下:

    public void dispatchMessage(Message msg) {
        //注意下面這行代碼
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
             //注意下面這行代碼
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
             //注意下面這行代碼
            handleMessage(msg);
        }
}

我們來分析下這段代碼:
1.首先會判斷msg.callback存不存在,如果msg.callback存在,這種情況下會執行handleCallback(msg), handleCallback源碼如下:

private static void handleCallback(Message message) {
        message.callback.run();
}

2.如果msg.callback就是null,代碼繼續往下執行,接著我們會判斷Handler的成員字段mCallback存不存在。mCallback是Hanlder.Callback類型的,我們在上面提到過,在Handler的構造函數中我們可以傳遞Hanlder.Callback類型的對象,該對象需要實現handleMessage方法,如果我們在構造函數中傳遞了該Callback對象,那麼我們就會讓Callback的handleMessage方法來處理Message。

3.如果我們在構造函數中沒有傳入Callback類型的對象,那麼mCallback就為null,那麼我們會調用Handler自身的hanldeMessage方法,該方法默認是個空方法,我們需要自己是重寫實現該方法。

綜上,我們可以看到Handler提供了三種途徑處理Message,而且處理有前後優先級之分:首先嘗試讓postXXX中傳遞的Runnable執行,其次嘗試讓Handler構造函數中傳入的Callback的handleMessage方法處理,最後才是讓Handler自身的handleMessage方法處理Message。

因此Small對mCallback進行hook實現的就是第二種處理方式,ActivityThreadHandlerCallback中具體代碼如下:

    private static class ActivityThreadHandlerCallback implements Handler.Callback {

        private static final int LAUNCH_ACTIVITY = 100;

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what != LAUNCH_ACTIVITY) return false;

            Object/*ActivityClientRecord*/ r = msg.obj;
            //獲取到r中的Intent對象
            Intent intent = ReflectAccelerator.getIntent(r);
            //使用unwrapIntent方法將插件的類名賦給targetClass
            String targetClass = unwrapIntent(intent);
            if (targetClass == null) return false;

            // 替換上插件類對應的activityInfo
            ActivityInfo targetInfo = sLoadedActivities.get(targetClass);
            ReflectAccelerator.setActivityInfo(r, targetInfo);
            return false;
        }
    }

代碼分析可知,handleMessage方法中主要
是將msg.obj中存根的activityInfo中變成插件類對應的activityInfo,以供後續實例Activity和調用onCreate時使用。

重點:
重寫的mCallback.handleMessage(msg)返回的是false,為什麼要這樣做呢?
這樣做的目的是為了實現在handler裡dispatchMessage方法中對Message的處理除了執行了第二種方式,還接著執行第三種方式。這樣做為了實現對源碼的輕度hook來達到將存根Activity替換為插件Activity的過程。

unwrapIntent()方法解析:

    private static String unwrapIntent(Intent intent) {
        //得到該intent對象中的所有category
        Set categories = intent.getCategories();
        if (categories == null) return null;

        //通過查找categories其中名為REDIRECT_FLAG的category來找到原來插件activity類名
        Iterator it = categories.iterator();
        while (it.hasNext()) {
            String category = it.next();
            if (category.charAt(0) == REDIRECT_FLAG) {
                //返回對應插件activity類名
                return category.substring(1);
            }
        }
        return null;
    }

app的生命周期調用最後都是由Instrumentation來執行,所以Small框架中定義的InstrumentationWrapper也對其中的callActivityOnCreate,callActivityOnStop,callActivityOnDestroy等方法進行了重寫,具體如下:

callActivityOnCreate()方法解析:

        @Override
        /**為插件准備資源*/
        public void callActivityOnCreate(Activity activity, android.os.Bundle icicle) {
            do {
                if (sLoadedActivities == null) break;
                ActivityInfo ai = sLoadedActivities.get(activity.getClass().getName());
                if (ai == null) break;
                //同步插件activity對應的窗口信息
                applyActivityInfo(activity, ai);
            } while (false);
            //調用原Instrumentation的callActivityOnCreate方法
            sHostInstrumentation.callActivityOnCreate(activity, icicle);

            //如果它被其他的應用程序修改了一些,復位原先的activity instrumentation
            if (sBundleInstrumentation != null) {
                try {
                    Field f = Activity.class.getDeclaredField("mInstrumentation");
                    f.setAccessible(true);
                    Object instrumentation = f.get(activity);
                    if (instrumentation != sBundleInstrumentation) {
                        f.set(activity, sBundleInstrumentation);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

applyActivityInfo()方法解析:

    /**
     * 申請的插件Activity信息是與插件的AndroidManifest.xml裡面一樣
     * @param activity
     * @param ai
     */
    private static void applyActivityInfo(Activity activity, ActivityInfo ai) {
        // Apply window attributes
        Window window = activity.getWindow();
        window.setSoftInputMode(ai.softInputMode);
        activity.setRequestedOrientation(ai.screenOrientation);
    }

callActivityOnStop方法解析:

        @Override
        public void callActivityOnStop(Activity activity) {
            sHostInstrumentation.callActivityOnStop(activity);

            if (!Small.isUpgrading()) return;

            // If is upgrading, we are going to kill self while application turn into background,
            // and while we are back to foreground, all the things(code & layout) will be reload.
            // Don't worry about the data missing in current activity, you can do all the backups
            // with your activity's `onSaveInstanceState' and `onRestoreInstanceState'.

            // Get all the processes of device (1)
            ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
            List processes = am.getRunningAppProcesses();
            if (processes == null) return;

            // Gather all the processes of current application (2)
            // Above 5.1.1, this may be equals to (1), on the safe side, we also
            // filter the processes with current package name.
            String pkg = activity.getApplicationContext().getPackageName();
            final List currentAppProcesses = new ArrayList<>(processes.size());
            for (RunningAppProcessInfo p : processes) {
                if (p.pkgList == null) continue;

                boolean match = false;
                int N = p.pkgList.length;
                for (int i = 0; i < N; i++) {
                    if (p.pkgList[i].equals(pkg)) {
                        match = true;
                        break;
                    }
                }
                if (!match) continue;

                currentAppProcesses.add(p);
            }
            if (currentAppProcesses.isEmpty()) return;

            // The top process of current application processes.
            RunningAppProcessInfo currentProcess = currentAppProcesses.get(0);
            if (currentProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return;

            // Seems should delay some time to ensure the activity can be successfully
            // restarted after the application restart.
            // FIXME: remove following thread if you find the better place to `killProcess'

            new Thread() {
                @Override
                public void run() {
                    try {
                        sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    for (RunningAppProcessInfo p : currentAppProcesses) {
                        android.os.Process.killProcess(p.pid);
                    }
                }
            }.start();
        }

callActivityOnDestroy()方法解析:

        @Override
        public void callActivityOnDestroy(Activity activity) {
            do {
                if (sLoadedActivities == null) break;
                String realClazz = activity.getClass().getName();
                ActivityInfo ai = sLoadedActivities.get(realClazz);
                if (ai == null) break;
                //存根activity與真實activity解綁
                inqueueStubActivity(ai, realClazz);
            } while (false);
            //調用原Instrumentation的callActivityOnDestroy方法
            sHostInstrumentation.callActivityOnDestroy(activity);
        }

在調用到callActivityOnDestroy時,需要將存根activity與真實activity解綁,主要通過inqueueStubActivity方法實現:

        private void inqueueStubActivity(ActivityInfo ai, String realActivityClazz) {
            if (ai.launchMode == ActivityInfo.LAUNCH_MULTIPLE) return;
            if (mStubQueue == null) return;
            int countForMode = STUB_ACTIVITIES_COUNT;
            int offset = (ai.launchMode - 1) * countForMode;
            for (int i = 0; i < countForMode; i++) {
                String stubClazz = mStubQueue[i + offset];
                if (stubClazz != null && stubClazz.equals(realActivityClazz)) {
                    mStubQueue[i + offset] = null;
                    break;
                }
            }
        }

從ActivityInfo獲取launchMode,通過啟動模式和插件Activity類名找到對存根Activity對應的mStubQueue數組位置並將其賦值為null,這樣就實現了解綁。

1、由於我們欺騙了 AMS , AMS 應該只知道 StubActivity 的存在,它壓根兒就不知道TargetActivity是什麼,為什麼它能正確完成對TargetActivity生命周期的回調呢?

一切的秘密在 token 裡面。 AMS 與 ActivityThread 之間對於Activity的生命周期的交互,並沒有直接使用Activity對象進行交互,而是使用一個token來標識,這個token是binder對象,因此可以方便地跨進程傳遞。Activity裡面有一個成員變量 mToken 代表的就是它,token可以唯一地標識一個Activity對象,它在Activity的 attach 方法裡面初始化;
在 AMS 處理Activity的任務棧的時候,使用這個token標記Activity,因此在Small裡面, AMS 進程裡面的token對應的是StubActivity,也就是 AMS 還在傻乎乎地操作StubActivity(關於這一點,你可以dump出任務棧的信息,可以觀察到dump出的確實是StubActivity)。但是在我們App進程裡面,token對應的卻是TargetActivity!因此,在ActivityThread執行回調的時候,能正確地回調到TargetActivity相應的方法。

2、為什麼App進程裡面,token對應的是TargetActivity呢?
回到代碼,ActivityClientRecord是在 mActivities 裡面取出來的,確實是根據token取;那麼這個token是什麼時候添加進去的呢?我們看performLaunchActivity就完成明白了:它通過classloader加載了TargetActivity,然後完成一切操作之後把這個activity添加進了 mActivities !另外,在這個方法裡面我們還能看到對Ativity attact 方法的調用,它傳遞給了新創建的Activity一個token對象,而這個token是在ActivityClientRecord構造函數裡面初始化的。
至此我們已經可以確認,通過這種方式啟動的Activity有它自己完整而獨立的生命周期!

最後總結:至此,我們對Small框架中解決“Activity注冊和生命周期問題”,從原理和代碼兩方面做了一個全面的分析。這個過程中,我弄懂了Android的activity啟動流程,領會了Small框架怎麼通過輕度hook實現對Android插件化的。寫了這兩篇博文,希望對你有幫助。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved