AMS启动流程以及Hook该流程

10,062 阅读8分钟
AMS启动流程图

首先来看一下这张流程图,时常看看这个图有助于我们理解Android AMS的启动流程,脑中形成一个大概的启动流程体系,里面包含如下内容:

  • SystemServer启动流程
  • AMS具体方法启动逻辑
  • APP进程的启动流程
  • startActivity的启动流程

startBootstrapServices中mActivityManagerService.setSystemProcess设置SystemServer,这里也设置各种服务设置到ServiceManager,为了以后服务通过Binder进行通信

与Activity管理有关的数据结构
ActivityRecord(An entry in the history stack,representing an activity)

ActivityRecord中存在着大量的成员变量,包含了一个Activity的所有信息。ActivityRecord中的成员变量task表示其所在的TaskRecord,由此可以看出:ActivityRecord与TaskRecord建立了联系

TaskRecord

TaskRecord,内部维护一个ArrayList<ActivityRecord>用来保存ActivityRecord,TaskRecord中的mStack表示其所在的ActivityStack,startActivity()时也会创建一个TaskRecord

ActivityStackSupervisor
ActivityStack mHomeStack; //管理的是launcher相关的任务
ActivityStack mFocusedStack; //管理非Launcher相关的任务

Android系统的一些服务

Android系统通过SystemServiceManager管理Java层的各种服务启动,大概有80多种服务,放入一个ArrayList中

可以看一下Android系统的一些服务,这里参考的是深入理解Android的书中的内容,并非官方标准的区分。

· 位于第一大类的是Android的核心服务,如ActivityManagerService、WindowManagerService等。

· 位于第二大类的是和通信相关的服务,如Wifi相关服务、Telephone相关服务。

· 位于第三大类的是和系统功能相关的服务,如AudioService、MountService、UsbService等。

· 位于第四大类的是BatteryService、VibratorService等服务。

· 位于第五大类的是EntropyService,DiskStatsService、Watchdog等相对独立的服务。

· 位于第六大类的是蓝牙服务。

· 位于第七大类的是UI方面的服务,如状态栏服务,通知管理服务等。

Activity启动流程相关

ApplicationThread是一个Binder,通过Handler进行跨线程通信,走到ActivityThread

应用没有启动时,点击app,一定会调用startProcessLocked()函数,通过zogyte去fork一个app进程,接下来就是应用进程和AMS两者的事情了,应用进程去调用AMS的方法,比如startActivity,很容易调用,因为AMS是一个有名称的Binder服务,在任意的地方都可以通过在ServiceManager(SM)里面查询拿到代理类,应用进程fork完第一件事情就是进行attach,attach过程就是为了把我的代理类交给AMS,应用进程有AMS的代理类对象,AMS也有应用进程的代理类对象,接下来这两者就可以进行交流了,这个就是startActivity的启动流程了。

SM的获取Acitivity的Binder服务

代理的设置过程

Activity Manager的组成主要分为以下几个部分:

1.服务代理:由ActivityManagerProxy实现,用于与Server端提供的系统服务进行进程间通信

2.服务中枢:ActivityManagerNative继承自Binder并实现IActivityManager,它提供了服务接口和 Binder接口的相互转化功能,并在内部存储服务代理对像,并提供了getDefault方法返回服务代理

3.Client:由ActivityManager封装一部分服务接口供Client调用。ActivityManager内部通过调用 ActivityManagerNative的getDefault方法,可以得到一个ActivityManagerProxy对像的引用,进而通过 该代理对像调用远程服务的方法

4.Server:由ActivityManagerService实现,提供Server端的系统服务

时序图

Activity在AMS中是一个ActivityRecord对象存在的,一个Activity对应一个ActivityRecord,ActivityRecord中存在着大量的成员变量,包含了一个Activity的所有信息。 ActivityRecord中的成员变量task表示其所在的TaskRecord。ActivityRecord是在startActivity的时候创建的。

相关的知识点:
  1. 微信双开,选择哪一个微信,或者pdf文件打开的时候,有多个选择,是在这里进行收集的,根据intent的action

  1. Instrumentation理解

Android instrumentation是Android系统里面的一套控制方法或者“钩子”,这些钩子可以在正常的生命周期(正常是有操作系统控制的)之外控制Android控件的运行,其实指的就是Instrumentation类提供的各种流程控制方法。

app->instrumentation->ams->app ,自动化测试是可以通过操作Instrumentation来操作Activity等,这个Instrumentation相当于设计了一个统一的入口

3. ActivityThread不是线程类(Thread),只不过它会跑在UI主线程中,ActivityThead.main方法中,UI主线程中会有一个looper

Binder通信相关

天然的带有调用者的身份信息uid,验证调用者是不是有这个权限

id需要恢复,所以需要有这么一个流程。

Hook Activity启动流程

首先需要了解上面的Activity的启动流程,简单介绍如下:

  1. AMS(验证Activity是否注册),不能传targetActivity

    传一个假的StubActivity,return success,然后StubActivity替换回targetActivity

  2. 回到app进程后(Instrumentation 创建Activity)

  3. AMS控制 Instrumentation执行Activity生命周期

我们需要欺骗AMS,然后启动真正的TargetActivity,Hook有起始点和终点。这里需要寻找两个地方的hook点,一个是对Intent中Activity的替换(hookIActivityTaskManager方法),一个是对Intent中Activity的还原(hookHandler)。

import android.app.Activity;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import com.jackie.activityhookdemo.StubActivity;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

public class HookHelper {
    private static final String TAG = "Jackie";

    public static final String EXTRA_TARGET_INTENT = "extra_target_intent";

    public static void hookAMSAidl(){
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P){
            hookIActivityTaskManager();
        }else{
            hookIActivityManager();
        }
    }

    public static void hookIActivityTaskManager(){
        try{
            Field singletonField = null;
            Class<?> actvityManager = Class.forName("android.app.ActivityTaskManager");
            singletonField = actvityManager.getDeclaredField("IActivityTaskManagerSingleton");
            singletonField.setAccessible(true);
            Object singleton = singletonField.get(null);
            //拿IActivityManager对象
            Class<?> singletonClass = Class.forName("android.util.Singleton");
            Field mInstanceField = singletonClass.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            //原始的IActivityTaskManager
            final Object IActivityTaskManager = mInstanceField.get(singleton);

            Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                    , new Class[]{Class.forName("android.app.IActivityTaskManager")}
                    , new InvocationHandler() {
                        @Override
                        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
//                            Log.i(TAG, "invoke: " + method.getName());

                            //偷梁换柱
                            //真正要启动的activity目标
                            Intent raw = null;
                            int index = -1;
                            if ("startActivity".equals(method.getName())) {
                                Log.i(TAG, "invoke: startActivity 启动准备");
                                for (int i = 0; i < args.length; i++) {
                                    if(args[i] instanceof  Intent){
                                        raw = (Intent)args[i];
                                        index = i;
                                    }
                                }
                                Log.i(TAG, "invoke: raw: " + raw);
                                //代替的Intent
                                Intent newIntent = new Intent();
                                newIntent.setComponent(new ComponentName("com.jackie.activityhookdemo", StubActivity.class.getName()));
                                newIntent.putExtra(EXTRA_TARGET_INTENT,raw);

                                args[index] = newIntent;

                            }

                            return method.invoke(IActivityTaskManager, args);
                        }
                    });

            //            7. IActivityManagerProxy 融入到framework
            mInstanceField.set(singleton, proxy);

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void hookIActivityManager() {

        try{
            Field singletonField = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Class<?> actvityManager = Class.forName("android.app.ActivityManager");
                singletonField = actvityManager.getDeclaredField("IActivityManagerSingleton");
            } else {
                Class<?> actvityManager = Class.forName("android.app.ActivityManagerNative");
                singletonField = actvityManager.getDeclaredField("gDefault");
            }
            singletonField.setAccessible(true);
            Object singleton = singletonField.get(null);
            //拿IActivityManager对象
            Class<?> actvityManager = Class.forName("android.util.Singleton");
            Field mInstanceField = actvityManager.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            //原始的IActivityManager
            final Object rawIActivityManager = mInstanceField.get(singleton);
            //创建一个IActivityManager代理对象
            Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                    , new Class[]{Class.forName("android.app.IActivityManager")}
                    , new InvocationHandler() {
                        @Override
                        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
//                            Log.i(TAG, "invoke: " + method.getName());

                            //偷梁换柱
                            //真正要启动的activity目标
                            Intent raw = null;
                            int index = -1;
                            if ("startActivity".equals(method.getName())) {
                                Log.i(TAG, "invoke: startActivity 启动准备");
                                for (int i = 0; i < args.length; i++) {
                                    if(args[i] instanceof  Intent){
                                        raw = (Intent)args[i];
                                        index = i;
                                    }
                                }
                                Log.i(TAG, "invoke: raw: " + raw);
                                //代替的Intent
                                Intent newIntent = new Intent();
                                newIntent.setComponent(new ComponentName("com.jackie.activityhookdemo", StubActivity.class.getName()));
                                newIntent.putExtra(EXTRA_TARGET_INTENT,raw);

                                args[index] = newIntent;

                            }

                            return method.invoke(rawIActivityManager, args);
                        }
                    });

            //            7. IActivityManagerProxy 融入到framework
            mInstanceField.set(singleton, proxy);

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public static void hookHandler() {
        try {
            Class<?> atClass = Class.forName("android.app.ActivityThread");
            Field sCurrentActivityThreadField = atClass.getDeclaredField("sCurrentActivityThread");
            sCurrentActivityThreadField.setAccessible(true);
            Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);
            //ActivityThread 一个app进程 只有一个,获取它的mH
            Field mHField = atClass.getDeclaredField("mH");
            mHField.setAccessible(true);
            final Handler mH = (Handler) mHField.get(sCurrentActivityThread);

            //获取mCallback
            Field mCallbackField = Handler.class.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);

            mCallbackField.set(mH, new Handler.Callback() {

                @Override
                public boolean handleMessage(Message msg) {
                    Log.i(TAG, "handleMessage: " + msg.what);
                    switch (msg.what) {
                        case 100: {

                        }
                        break;
                        case 159: {
                            Object obj = msg.obj;
                            Log.i(TAG, "handleMessage: obj=" + obj);
                            try {
                                Field mActivityCallbacksField = obj.getClass().getDeclaredField("mActivityCallbacks");
                                mActivityCallbacksField.setAccessible(true);
                                List mActivityCallbacks = (List) mActivityCallbacksField.get(obj);
                                Log.i(TAG, "handleMessage: mActivityCallbacks= " + mActivityCallbacks);
                                //注意了 这里如果有同学debug调试会发现第一次size=0 原因如下
                                //在Android O之前
                                //public static final int LAUNCH_ACTIVITY         = 100;
                                //public static final int PAUSE_ACTIVITY          = 101;
                                //public static final int PAUSE_ACTIVITY_FINISHING= 102;
                                //public static final int STOP_ACTIVITY_SHOW      = 103;
                                //public static final int STOP_ACTIVITY_HIDE      = 104;
                                //public static final int SHOW_WINDOW             = 105;
                                //public static final int HIDE_WINDOW             = 106;
                                //public static final int RESUME_ACTIVITY         = 107;
                                //public static final int SEND_RESULT             = 108;
                                //public static final int DESTROY_ACTIVITY        = 109;
                                //end
                                //从AndroidP开始重构了状态模式
                                //public static final int EXECUTE_TRANSACTION = 159;
                                // 首先一个app 只有一个ActivityThread 然后就只有一个mH
                                //我们app所有的activity的生命周期的处理都在mH的handleMessage里面处理
                                //在Android 8.0之前,不同的生命周期对应不同的msg.what处理
                                //在Android 8.0 改成了全部由EXECUTE_TRANSACTION来处理
                                //所以这里第一次mActivityCallbacks是MainActivity的生命周期回调的
//                                handleMessage: 159
//                                handleMessage: obj=android.app.servertransaction.ClientTransaction@efd342
//                                handleMessage: mActivityCallbacks= []
//                                invoke: method activityPaused
//                                handleMessage: 159
//                                handleMessage: obj=android.app.servertransaction.ClientTransaction@4962
//                                handleMessage: mActivityCallbacks= [WindowVisibilityItem{showWindow=true}]
//                                handleMessage: size= 1
//                                handleMessage: 159
//                                handleMessage: obj=android.app.servertransaction.ClientTransaction@9e98c6b
//                                handleMessage: mActivityCallbacks= [LaunchActivityItem{intent=Intent { cmp=com.zero.activityhookdemo/.StubActivity (has extras) },ident=168243404,info=ActivityInfo{5b8d769 com.zero.activityhookdemo.StubActivity},curConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h659dp 420dpi nrml port finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 0 - 1080, 1794) mWindowingMode=fullscreen mActivityType=undefined} s.6},overrideConfig={1.0 310mcc260mnc [en_US] ldltr sw411dp w411dp h659dp 420dpi nrml port finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 1794) mAppBounds=Rect(0, 0 - 1080, 1794) mWindowingMode=fullscreen mActivityType=standard} s.6},referrer=com.zero.activityhookdemo,procState=2,state=null,persistentState=null,pendingResults=null,pendingNewIntents=null,profilerInfo=null}]
//                                handleMessage: size= 1
                                if (mActivityCallbacks.size() > 0) {
                                    Log.i(TAG, "handleMessage: size= " + mActivityCallbacks.size());
                                    String className = "android.app.servertransaction.LaunchActivityItem";
                                    if (mActivityCallbacks.get(0).getClass().getCanonicalName().equals(className)) {
                                        Object object = mActivityCallbacks.get(0);
                                        Field intentField = object.getClass().getDeclaredField("mIntent");
                                        intentField.setAccessible(true);
                                        Intent intent = (Intent) intentField.get(object);
                                        Intent targetIntent = intent.getParcelableExtra(EXTRA_TARGET_INTENT);
                                        intent.setComponent(targetIntent.getComponent());
                                    }
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }
                        break;
                    }
                    mH.handleMessage(msg);
                    return true;
                }
            });

        } catch (Exception e) {
            Log.e(TAG, "hookHandler: " + e.getMessage());
            e.printStackTrace();
        }
    }




    public static void hookInstrumentation(Activity activity) {
        //TODO:
        Class<?> activityClass = Activity.class;
        //通过Activity.class 拿到 mInstrumentation字段
        Field field = null;
        try {
            field = activityClass.getDeclaredField("mInstrumentation");
            field.setAccessible(true);
            //根据activity内mInstrumentation字段 获取Instrumentation对象
            Instrumentation instrumentation = (Instrumentation) field.get(activity);
            //创建代理对象,注意了因为Instrumentation是类,不是接口 所以我们只能用静态代理,
            Instrumentation instrumentationProxy = new ProxyInstrumentation(instrumentation);
            //进行替换
            field.set(activity, instrumentationProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    static class ProxyInstrumentation extends Instrumentation {

        private static final String TAG = "Zero";
        // ActivityThread中原始的对象, 保存起来
        Instrumentation mBase;

        public ProxyInstrumentation(Instrumentation base) {
            mBase = base;
        }

        public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {

            Log.d(TAG, "执行了startActivity, 参数如下: " + "who = [" + who + "], " +
                    "contextThread = [" + contextThread + "], token = [" + token + "], " +
                    "target = [" + target + "], intent = [" + intent +
                    "], requestCode = [" + requestCode + "], options = [" + options + "]");

            // 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
            //execStartActivity有重载,别找错了
            try {
                Method execStartActivity = Instrumentation.class.getDeclaredMethod(
                        "execStartActivity",
                        Context.class, IBinder.class, IBinder.class, Activity.class,
                        Intent.class, int.class, Bundle.class);
                execStartActivity.setAccessible(true);
                return (ActivityResult) execStartActivity.invoke(mBase, who,
                        contextThread, token, target, intent, requestCode, options);
            } catch (Exception e) {
                throw new RuntimeException("do not support!!! pls adapt it");
            }
        }

        /**
         * 重写newActivity 因为newActivity 方法有变
         * 原来是:(Activity)cl.loadClass(className).newInstance();
         *
         * @param cl
         * @param className
         * @param intent
         * @return
         * @throws InstantiationException
         * @throws IllegalAccessException
         * @throws ClassNotFoundException
         */
        @Override
        public Activity newActivity(ClassLoader cl, String className,
                                    Intent intent)
                throws InstantiationException, IllegalAccessException,
                ClassNotFoundException {

            return mBase.newActivity(cl, className, intent);
        }
    }

    public static void hookActivityThreadInstrumentation() {
        //TODO:
        try {
            // 先获取到当前的ActivityThread对象
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            //currentActivityThread是一个static函数所以可以直接invoke,不需要带实例参数
            Object currentActivityThread = currentActivityThreadMethod.invoke(null);

            // 拿到原始的 mInstrumentation字段
            Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
            mInstrumentationField.setAccessible(true);
            Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
            // 创建代理对象
            Instrumentation proxyInstrumentation = new ProxyInstrumentation(mInstrumentation);
            // 偷梁换柱
            mInstrumentationField.set(currentActivityThread, proxyInstrumentation);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

参考文章:juejin.cn/post/684490…