插件化学习记录

2019-10-18  本文已影响0人  nullpt

1.插件化知识相关

插件化简介(此处省略若干字,,,)

这篇文章主要是自己学习的记录,不实用~~~

2.插件化工作大体流程

3.Activity的插件化

接下来跳过加载apk,ClassLoader解析过程,通过Activity插件化的样例讲解如何通过代理和反射替换并使用插件工作;

首先需要说明一点的是,启动一个完全没有在AndroidManifest注册的Activity是不可能的。因为在启动的过程中,存在一个校验的过程,而这个校验则是由PMS来完成的,这个我们无法干预。因此,Activity的插件化方案大多使用占坑的思想。不同的是如何在检验之前替换,在生成对象的时候还原。

由于系统源代码过于繁杂,这里通过 极极极极极极简化版 的样例,简介通过hook实现插件化的思想

代码:
package com.baiguoqing.test;

import com.baiguoqing.test.activity.ActivityMain;
import com.baiguoqing.test.activity.ActivitySub;
import com.baiguoqing.test.activity.ActivityTest;
import com.baiguoqing.test.app.MyApp;

public class AndroidManifest {

    /**
     * 模拟配置 application
     */
    public static String DEFAULT_LAUNCHER_APPLICATION = MyApp.MyAppClass;

    /**
     * 模拟配置 launcher activity
     */
    public static String DEFAULT_LAUNCHER_ACTIVITY = ActivityMain.ActivityMainClass;

    /**
     * 模拟配饰 registered activity
     */
    public static String[] REGISTERED_ACTIVITY = new String[]{
            DEFAULT_LAUNCHER_ACTIVITY,
            ActivityTest.ActivityTestClass,
            /*实现组件化占位Activity:ActivitySub*/
            ActivitySub.ActivitySubClass
    };
}
package com.baiguoqing.android;

public interface IBinder {

    /**
     * 创建 application
     */
    Application newApplication(String appName);

    /**
     * 检查 activity
     */
    boolean checkActivity(String className);

    /**
     * 创建 activity
     */
    Activity newActivity(String className);

}
package com.baiguoqing.android;

public interface IActivityManager {

    /**
     * 开启 application
     */
    void startApplication(IBinder binder);

    /**
     * 开启 launcher activity
     */
    void startLauncherActivity(IBinder binder);

    /**
     * 开启指定activity
     */
    void startActivity(IBinder binder, String className);

    /**
     * 获取操作binder
     */
    IBinder getDefault();

    /**
     * 获取全局application
     */
    Application getApplication();

}
package com.baiguoqing.android;

import com.baiguoqing.test.AndroidManifest;

public class Binder implements IBinder {

    @Override
    public Application newApplication(String appName) {
        try {
            Class<?> clazz = Class.forName(appName);
            return (Application) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean checkActivity(String className) {
        for (String s : AndroidManifest.REGISTERED_ACTIVITY) {
            if (s.equals(className)) {
                /*do something*/
                return true;
            }
        }
        return false;
    }

    @Override
    public Activity newActivity(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            return (Activity) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
package com.baiguoqing.android;

import com.baiguoqing.test.AndroidManifest;

public class ActivityManager implements IActivityManager {

    /**
     * 全局 application
     */
    private Application mApplication;

    @Override
    public void startApplication(IBinder binder) {
        mApplication = binder.newApplication(AndroidManifest.DEFAULT_LAUNCHER_APPLICATION);
        mApplication.onCreate();
    }

    @Override
    public void startLauncherActivity(IBinder binder) {
        startActivity(binder, AndroidManifest.DEFAULT_LAUNCHER_ACTIVITY);
    }

    @Override
    public void startActivity(IBinder binder, String className) {
        if (binder.checkActivity(className)) {
            Activity activity = binder.newActivity(className);
            activity.onCreate();
            return;
        }
        throw new RuntimeException("startActivity fail, " + className + " not register");
    }

    @Override
    public Application getApplication() {
        return mApplication;
    }

    @Override
    public IBinder getDefault() {
        return new Binder();
    }
}
package com.baiguoqing.android;

public class Singleton {

    private static IActivityManager mManagerInstance = new ActivityManager();

    public static IActivityManager getInstance() {
        if (mManagerInstance == null) {
            synchronized (Singleton.class) {
                if (mManagerInstance == null) {
                    return new ActivityManager();
                }
            }
        }
        return mManagerInstance;
    }

}
package com.baiguoqing.android;

public class Application {

    public Application() {
    }

    public void onCreate() {
        /*maybe do something*/
    }

}
package com.baiguoqing.android;

public class Activity {

    private IActivityManager mManager = Singleton.getInstance();

    public Activity() {
    }

    public void onCreate() {
        /*maybe do something*/
    }

    public void startActivity(String className) {
        mManager.startActivity(mManager.getDefault(), className);
    }

    public Application getApplication() {
        return mManager.getApplication();
    }
}
package com.baiguoqing.android;

public class Main {
    /**
     * 模拟 Thread
     */
    public static void main(String[] args) {
        new Thread(() -> {
            IActivityManager manager = Singleton.getInstance();
            manager.startApplication(manager.getDefault());
            manager.startLauncherActivity(manager.getDefault());
        }).start();
    }
}
package com.baiguoqing.test.activity;

import com.baiguoqing.android.Activity;

/**
 * 测试开启Activity
 */
public class ActivityTest extends Activity {

    public static final String ActivityTestClass = "com.baiguoqing.test.activity.ActivityTest";

    private static final String ActivityTestTag = "ActivityTest created";

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println(ActivityTestTag);
    }
}
package com.baiguoqing.test.activity;

import com.baiguoqing.android.Activity;

/**
 * 插件Activity
 */
public class ActivityTarget extends Activity {

    public static final String ActivityTargetClass = "com.baiguoqing.test.activity.ActivityTarget";

    private static final String ActivityTargetTag = "ActivityTarget created";

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println(ActivityTargetTag);
    }
}
package com.baiguoqing.test.activity;

import com.baiguoqing.android.Activity;

/**
 * 占坑Activity
 */
public class ActivitySub extends Activity {

    public static final String ActivitySubClass = "com.baiguoqing.test.activity.ActivitySub";

    private static final String ActivitySubTag = "ActivitySub created";

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println(ActivitySubTag);
    }
}
package com.baiguoqing.test.activity;

import com.baiguoqing.android.Activity;

/**
 * 主启动Activity
 */
public class ActivityMain extends Activity {

    public static final String ActivityMainClass = "com.baiguoqing.test.activity.ActivityMain";

    private static final String ActivityMainTag = "ActivityMain created";

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println(ActivityMainTag);

        //开启其他activity
        startActivity(ActivityTest.ActivityTestClass);

        //开启组件activity
        startActivity(ActivityTarget.ActivityTargetClass);
    }
}

如上代码启动Thread后,报错:

ActivityMain created
ActivityTest created
Exception in thread "Thread-0" java.lang.RuntimeException: startActivity fail, com.baiguoqing.test.activity.ActivityTarget not register
    at com.baiguoqing.android.ActivityManager.startActivity(ActivityManager.java:30)
    at com.baiguoqing.android.Activity.startActivity(Activity.java:15)
    at com.baiguoqing.test.activity.ActivityMain.onCreate(ActivityMain.java:23)
    at com.baiguoqing.android.ActivityManager.startActivity(ActivityManager.java:27)
    at com.baiguoqing.android.ActivityManager.startLauncherActivity(ActivityManager.java:20)
    at com.baiguoqing.android.Main.lambda$main$0(Main.java:12)
    at java.base/java.lang.Thread.run(Thread.java:830)

Process finished with exit code 0

解决方案:占坑思想,钩住关键节点,代理

package com.baiguoqing.test.proxy;

import com.baiguoqing.test.activity.ActivityMain;
import com.baiguoqing.test.activity.ActivitySub;
import com.baiguoqing.test.activity.ActivityTarget;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class BinderProxy implements InvocationHandler {

    private Object mObject;

    public BinderProxy(Object mObject) {
        this.mObject = mObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("checkActivity".equals(method.getName())) {
            if (ActivityTarget.ActivityTargetClass.equals(args[0])) {
                args[0] = ActivitySub.ActivitySubClass;
                return method.invoke(mObject, args);
            }
        }
        try {
            return method.invoke(mObject, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
package com.baiguoqing.test.proxy;

import com.baiguoqing.android.IBinder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ActivityManagerProxy implements InvocationHandler {

    private Object mObject;
    private IBinder mBinder;

    public ActivityManagerProxy(Object object, IBinder binder) {
        this.mObject = object;
        this.mBinder = binder;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("getDefault".equals(method.getName())) {
            return Proxy.newProxyInstance(
                    Thread.currentThread().getContextClassLoader(),
                    new Class[]{IBinder.class},
                    new BinderProxy(mBinder));
        }
        try {
            return method.invoke(mObject, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

这里实现了ActivityManager和Binder类的代理,并且拦截了ActivityManager方法getDefault(),并且返回Binder的代理类;在Binder代理类中,调用checkActivity()方法时进行了修改,让其去检测占坑的Activity;

钩子注册

package com.baiguoqing.test.app;

import com.baiguoqing.android.Application;
import com.baiguoqing.android.IActivityManager;
import com.baiguoqing.android.IBinder;
import com.baiguoqing.test.proxy.ActivityManagerProxy;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyApp extends Application {

    public static final String MyAppClass = "com.baiguoqing.test.app.MyApp";
    private static final String MyAppTag = "My Application created";

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println(MyAppTag);
        try {
            hookActivityManager();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 钩子,用于跳过Activity检测
     */
    private void hookActivityManager() throws Exception {
        Field mManagerField = Class.forName("com.baiguoqing.android.Singleton").getDeclaredField("mManagerInstance");
        mManagerField.setAccessible(true);
        Object object1 = mManagerField.get(null);
        Method method = Class.forName("com.baiguoqing.android.ActivityManager").getDeclaredMethod("getDefault");
        method.setAccessible(true);
        IBinder binder = (IBinder) method.invoke(object1);
        IActivityManager managerProxy = (IActivityManager) Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{IActivityManager.class},
                new ActivityManagerProxy(object1, binder)
        );
        mManagerField.set(object1, managerProxy);
    }
}
My Application created
ActivityMain created
ActivityTest created
ActivityTarget created

Process finished with exit code 0

总的来说,这个小系统能hook的点有很多,这里列举了一个比较简单且清晰的点;
实际做插件开发时,四大组件的实现方式各有不同,但是思想和这个差不多,就是需要对系统原理具备充分的了解和掌握,这样才能找到合适的hook点;
目前插件化的方案还是有很多,这里只是列举了一个最为传统好理解的实现方式;

上一篇下一篇

猜你喜欢

热点阅读