1. 程式人生 > >Android 外掛化分析(3)- Activity啟動流程

Android 外掛化分析(3)- Activity啟動流程

在真正分析外掛化技術前,我們必須瞭解一些必要的關於Android四大元件的相關知識。

以Activity為例,我們需要了解Activity啟動過程,才能有效的進行Hook實現外掛化。

以Android 8.1為例

我們啟動一個Activity通常會使用startActivity方法,但是在Activity內部最終都會呼叫startActivityForResult方法

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ......
        } else {
            ......
        }
    }

在這個方法的內部實際是呼叫Instrumentation類的execStartActivity方法。

在這裡我們遇到了三個非常重要的類。

  1. Instrumentation : 隨著Activity內部會持有一個對Instrumentation的引用,
  2. ActivityThread : 主執行緒,在app啟動的時候建立的,代表了Android應用程式,裡面包含了Main函式
  3. ApplicationThread : App端在system程序的代理類(涉及到Binder機制)

接著會呼叫Instrumentation內部的execStartAcivitiesAsUser方法

    public void execStartActivitiesAsUser(Context who, IBinder contextThread,
            IBinder token, Activity target, Intent[] intents, Bundle options,
            int userId) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ......
        try {
            .......
            int result = ActivityManager.getService()
                .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
                        token, options, userId);
            checkStartActivityResult(result, intents[0]);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }

然後我們進入ActivityManager內部,getService實際返回的是一個單例物件,持有AMS在app端的遠端代理物件。

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

所以從這裡就從app程序進入到system程序。

AMS裡的程式碼很多,邏輯非常複雜,只要知道AMS會對傳遞過來的Intent進行檢查,如果需要啟動的Activity沒有在manifest裡申明,就會把錯誤碼返回給Instrumentation,從而Instrumentation就會丟擲經典的ActivityNofFoundException異常。

如果通過AMS的檢查,那麼會回撥ApplicationThread的scheduleLauncherActivity方法

        @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<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            ......

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

給H傳送了一個LAUNCH_ACTIVITY的訊息

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


就正式開始了Activity的啟動過程。

從以上的分析,我們是無法啟動一個沒有manifest註冊的Activity,但是外掛化技術卻可以繞過AMS的檢查達到這樣一個目的。