频道栏目
首页 > 程序开发 > 移动开发 > Android > 正文
Android Small插件化框架--启动插件Activity源码解析(下)
2016-11-15 09:57:50         来源:qq_21920435的博客  
收藏   我要投稿

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插件化的。写了这两篇博文,希望对你有帮助。

点击复制链接 与好友分享!回本站首页
上一篇:Android新建工程步骤(AndroidStudio)
下一篇:Android中的语言和字符串资源
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站