美文网首页 移动 前端 Python Android Java面试
插件化(二)插件化Activity的启动

插件化(二)插件化Activity的启动

作者: zcwfeng | 来源:发表于2020-11-30 00:09 被阅读0次

    启动Activity

    我们启动Activity的方式

    正常一个进程app
    startActivity(new Intent(MainActivity.this,ProxyAcitvity.class));
    
    启动其他进程
           Intent intent = new Intent();
           intent.setComponent(new ComponentName("top.zcwfeng.plugin",
                   "top.zcwfeng.plugin.MainActivity"));
    

    但是我们启动的时候都需要进行注册。在AMS(ActivityManagerService)中进行注册。
    APP----AMS----APP

    所以我们用到的技术局势Hook: 通过 反射 和 动态代理实现。

    如何查找Hook点和思路

    偷梁换柱.png

    Activity------>AMS

    查找源码的Hook点

    Activity#startActivity 方法查看

    Activity-AMS.png

    Activity#startActivityForResult 三个参数方法

    instrumentation 这个位置是个hook点,但是我们继续看看有没有更轻松

     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);
                if (ar != null) {
                    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                        ar.getResultData());
                }
                if (requestCode >= 0) {
                    // If this start is requesting a result, we can avoid making
                    // the activity visible until the result is received.  Setting
                    // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                    // activity hidden during this time, to avoid flickering.
                    // This can only be done when a result is requested because
                    // that guarantees we will get information back when the
                    // activity is finished, no matter what happens to it.
                    mStartedActivity = true;
                }
    
                cancelInputsAndStartExitTransition(options);
                // TODO Consider clearing/flushing other event sources and events for child windows.
            } else {
                if (options != null) {
                    mParent.startActivityFromChild(this, intent, requestCode, options);
                } else {
                    // Note we want to go through this method for compatibility with
                    // existing applications that may have overridden it.
                    mParent.startActivityFromChild(this, intent, requestCode);
                }
            }
        }
    

    继续进入Instrumentation#execStartActivity

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            IApplicationThread whoThread = (IApplicationThread) contextThread;
            Uri referrer = target != null ? target.onProvideReferrer() : null;
            if (referrer != null) {
                intent.putExtra(Intent.EXTRA_REFERRER, referrer);
            }
            if (mActivityMonitors != null) {
                synchronized (mSync) {
                    final int N = mActivityMonitors.size();
                    for (int i=0; i<N; i++) {
                        final ActivityMonitor am = mActivityMonitors.get(i);
                        ActivityResult result = null;
                        if (am.ignoreMatchingSpecificIntents()) {
                            result = am.onStartActivity(intent);
                        }
                        if (result != null) {
                            am.mHits++;
                            return result;
                        } else if (am.match(who, null, intent)) {
                            am.mHits++;
                            if (am.isBlocking()) {
                                return requestCode >= 0 ? am.getResult() : null;
                            }
                            break;
                        }
                    }
                }
            }
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess(who);
                int result = ActivityManager.getService()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, options);
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
            return null;
        }
    

    找到 静态方法,并且有Intent相关的

    int result = ActivityManager.getService()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, options);
    

    这里让我们容易想到,可以用动态代理去修改Intent。反射对于静态方法比较容易。所以这里是突破口。

    接口+实现,比较容易想到
    source 26——8.0源码中

     /**
         * @hide
         */
        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;
                    }
                };
    

    反射拿到IActivityManager 获取 Singleton 对象

    ActivityManager.getService()---静态方法,后去返回---IActivityManager
    IActivityManger 对象---IActivityManagerSingleton get 获取---Singleton<T>#private T mInstance
    我们的proxyInstance 替换系统的 mInstance 对象
    mInstance 非静态的 -- Singleton的对象 ---- IActivityManagerSingleton 是静态的

     public static void hookAMS() {
            try {
    
                // 获取 Singleton 对象
                Class<?> clazz = Class.forName("android.app.ActivityManager");
                Field singletonField = clazz.getDeclaredField("IActivityManagerSingleton");
                singletonField.setAccessible(true);
                Object singleton = singletonField.get(null);
    
                // 获取 IActivityManager 对象
                Class<?> singletonClass = Class.forName("android.util.Singleton");
                Field mInstanceField = singletonClass.getDeclaredField("mInstance");
                mInstanceField.setAccessible(true);
                Object mInstance = mInstanceField.get(singleton);
    
                Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
                Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                        new Class[]{iActivityManagerClass}, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                //TODO Intent 的修改
    
    //TODO Intent 的修改---进行过滤
                                if ("startActivity".equals(method.getName())) {
                                    int index = -1;
                                    for (int i = 0; i < args.length; i++) {
                                        if (args[i] instanceof Intent) {
                                            index = i;
                                            break;
                                        }
                                    }
                                    Intent intent = (Intent) args[index];
    
                                    Intent proxyIntent = new Intent();
                                    proxyIntent.setClassName("top.zcwfeng.zcwplugin",
                                            "top.zcwfeng.zcwplugin.ProxyActivity");
                                    intent.putExtra(TARGET_INTENT, intent);
                                    args[index] = proxyIntent;
                                }
    
    
                                //iActivityManager 对象
                                return method.invoke(mInstance,args);
                            }
                        });
                // TODO: 替换
                //proxyInstance.startActivity()
                // ActivityManager.getService() 替换成ProxyActity Instance
                mInstanceField.set(singleton, proxyInstance);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    

    Activity 启动

    Activity 启动.png

    AMS----->ApplicationThread Hook Handler

    ActivityThread------>Activity

    ActvityThread流程.png

    ActivityThread#scheduleLaunchActivity----->sendMessage--->H

    所以我们要Hook Handler

            public static final int LAUNCH_ACTIVITY         = 100;
    
    

    我们的目标还是找Intent 先关方便替换的地方

    继续搜索
    ActvityThread#handleLaunchActivity-->performLaunchActivity
    -----> r.intent.getComponent();

    找到 Intent的方便替换的地方 --- 在这个类 ActivityClientRecord 里面 --- Intent 是非静态 -- 获取 ActivityClientRecord 对象(关键点)

    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
    看到这个,所以 r ---- 相当与msg.obj

    源码中Handler 对象H 是 final H mH = new H();

    因此我们需要到Handler#handlerMessage-------->
    Handler 源码

     public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    调用handlerMessage 之前,我们会执行mCallback
    所以我们可以借助mCallback
    mH 创建没有构造赋值过,所以 系统的mCallback == null

    思路:

    创建 mCallback 替换系统的 -- 从而拿到 msg --- msg.obj -- intent

    想要拿到Handler mCallBack 因为不是静态,我们就要拿到Handler,handler就是H类,mH 不是静态,我们就需要ActivityThread 找到
    private static volatile ActivityThread sCurrentActivityThread;

    静态的反射比较方便拿到。
    hookHandler

    public static void hookHandler() {
    
            // 拿到handler对象 mh,非静态,拿到ActivityThread是静态的
    
            try {
                Class<?> clazz = Class.forName("android.app.ActiityThread");
    
                //获取 ActivityThread 对象
                Field activityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
                activityThreadField.setAccessible(true);
                Object activityThread = activityThreadField.get(null);
    
                //获取 mh 对象
                Field mHField = clazz.getDeclaredField("mH");
                mHField.setAccessible(true);
                Handler mH = (Handler) mHField.get(activityThread);
    
                Field callbackField = Handler.class.getDeclaredField("mCallback");
                callbackField.setAccessible(true);
    
    
                // 创建callback
                Handler.Callback callback = new Handler.Callback() {
                    @Override
                    public boolean handleMessage(@NonNull Message msg) {
                        // 通过msg 拿到 Intent 换回 插件执行的Intent
    
    
                        switch (msg.what) {
                            case 100:
                                try {
                                    Field intentField = msg.obj.getClass().getDeclaredField("intent");
                                    intentField.setAccessible(true);
                                    // 启动代理Intent
                                    Intent proxyIntent = (Intent) intentField.get(msg.obj);
                                    // 启动插件Intent
                                    Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
                                    if (intent != null) {
                                        intentField.set(msg.obj, intent);
                                    }
    
    
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                break;
                        }
    
    
                        // 必须 return false 保证向下执行handlerMessage
                        return false;
                    }
                };
    
                // 替换系统callback
                callbackField.set(mH, callback);
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    适配(上面用的源代码是8.0 上的源码,所以我们需要适配)

    适配点:

    1.hookAMS

    Instrumentation.java ActivityManager.java

    AMS.png
     // 获取 Singleton 对象
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // 小于8.0
                    Class<?> clazz = Class.forName("android.app.ActivityManagerNative");
                    singletonField = clazz.getDeclaredField("gDefault");
                } else {
                    Class<?> clazz = Class.forName("android.app.ActivityManager");
                    singletonField = clazz.getDeclaredField("IActivityManagerSingleton");
                }
    
    1. hookHandler
    截屏2020-11-29 23.30.12.png

    API 26 H 类 从100 开始
    API 28 H 类 从110 开始 生命周期从100~109 合并成了一个类 159

    API28 startActivit.png

    ClientTransaction == msg.obj ---- private List<ClientTransactionItem> mActivityCallbacks;private List<ClientTransactionItem> mActivityCallbacks; -- -- ClientTransactionItem的子类

    private Intent mIntent; -- LaunchActivityItem 对象 -- private List<ClientTransactionItem> mActivityCallbacks;
    -- ClientTransaction == msg.obj

    try {
                                    // 获取 mActivityCallbacks 对象
                                    Field mActivityCallbacksField = msg.obj.getClass()
                                            .getDeclaredField("mActivityCallbacks");
    
                                    mActivityCallbacksField.setAccessible(true);
                                    List mActivityCallbacks = (List) mActivityCallbacksField.get(msg.obj);
    
                                    for (int i = 0; i < mActivityCallbacks.size(); i++) {
                                        if (mActivityCallbacks.get(i).getClass().getName()
                                                .equals("android.app.servertransaction.LaunchActivityItem")) {
                                            Object launchActivityItem = mActivityCallbacks.get(i);
    
                                            // 获取启动代理的 Intent
                                            Field mIntentField = launchActivityItem.getClass()
                                                    .getDeclaredField("mIntent");
                                            mIntentField.setAccessible(true);
                                            Intent proxyIntent = (Intent) mIntentField.get(launchActivityItem);
    
                                            // 目标 intent 替换 proxyIntent
                                            Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
                                            if (intent != null) {
                                                mIntentField.set(launchActivityItem, intent);
                                            }
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
    

    相关文章

      网友评论

        本文标题:插件化(二)插件化Activity的启动

        本文链接:https://www.haomeiwen.com/subject/wahkwktx.html