Activity插件化原理第二种方案:Hook IActivityManager

栏目: IOS · Android · 发布时间: 7年前

内容简介:温馨提示:阅读本文需要20-30分钟(一大波代码) 关注公众号:顾林海今天,我们来解决一个问题:人生一切难题,知识给你答案。
Activity插件化原理第二种方案:Hook IActivityManager

温馨提示:阅读本文需要20-30分钟(一大波代码) 关注公众号:顾林海

今天,我们来解决一个问题:

Activity插件化原理第二种方案:Hook IActivityManager

人生一切难题,知识给你答案。

第一种方案Hook Instrumentation已经顺利完成,接下来我们看第二个方案,还是看这段代码:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            //Activity启动
            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) {
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

复制代码

通过mInstrumentation的execStartActivity方法启动Activity,在execStartActivity方法中会获取AMS的代理,Android 7.0通过ActivityManagerNative的getDefault方法获取一个ActivityManagerProxy,这个ActivityManagerProxy内部封装了IBinder类型的ActivityManagerService的代理类,这样在应用程序进程中就可以通过这个ActivityManagerProxy与SystemServer进程的ActivityManagerProxy进行通信,而在Android 8.0去除了ActivityManagerProxy这个代理类,由IActivityManager代替,这里的IActivityManager.aidl通过AIDL工具自动生成IActivityManager.java。

Android 7.0-Activity启动

ActivityManager是一个和AMS相关联的类,它主要对运行中的Activity进行管理,ActivityManager中相关管理方法最终会通过ActivityManagerNative的getDefault方法来得到ActivityManagerProxy,再调用ActivityManagerProxy的相关管理方法,ActivityManagerProxy就是AMS的代理类,通过这个代理类就可以和AMS进行通信。

Android7.0的Activity启动过程会调用Instrumentation的execStartActivity方法,代码如下:

public ActivityResult execStartActivity(
        ...
        try {
            ...
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
复制代码

在execStartActivity方法中会调用ActivityManagerNative的getDefault方法来获取ActivityManagerProxy,ActivityManagerProxy又是AMS的代理类,这样的话就可以通过ActivityManagerProxy向AMS发送startActivity的请求。

ActivityManagerNative的getDefault方法的代码如下:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            ...
            IActivityManager am = asInterface(b);
            ...
            return am;
        }
    };

    static public IActivityManager getDefault() {
        return gDefault.get();
    }
复制代码

在getDefault方法中调用了gDefault的get方法,gDefault是一个单例类。通过ServiceManager的getService方法获取一个IBinder类型的AMS的引用,再将它通过asInterface方法转换成ActivityManagerProxy类型的对象。

asInterface方法:

static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        //检查本地进程是否有IActivityManager接口的实现
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        //本地进程没有IActivityManager接口的实现,将IBinder类型的AMS引用封装成AMP
        return new ActivityManagerProxy(obj);
    }
复制代码

在asInterface方法中分两种情况,首先会检查本地进程是否有IActivityManager接口的实现,如果有就直接返回;如果没有,就将IBinder类型的AMS引用封装成ActivityManagerProxy。

public abstract class ActivityManagerNative extends Binder implements IActivityManager{
    ...
    class ActivityManagerProxy implements IActivityManager{
        public ActivityManagerProxy(IBinder remote){
            mRemote = remote;
        }
                ...
    }
    ...
}
复制代码

ActivityManagerProxy是ActivityManagerNative的内部类,在ActivityManagerProxy的构造方法中将AMS的引用赋值给变量mRemote,这样在ActivityManagerProxy中就可以使用AMS了。

继续回到Instrumentation的execStartActivity方法,代码如下:

public ActivityResult execStartActivity(
        ...
        try {
            ...
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
复制代码

通过ActivityManagerNative的getDefault方法获取AMS的代理类ActivityManagerProxy,再调用ActivityManagerProxy的startActivity方法。

ActivityManagerProxy的startActivity方法:

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        ...
        //向AMS发送START_ACTIVITY_TRANSACTION类型的进程间通信请求
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
复制代码

在ActivityManagerProxy的startActivity方法中,通过mRemote,也就是AMS的引用,向服务端的AMS发送一个START_ACTIVITY_TRANSACTION类型的进程间通信请求,服务端AMS就会从Binder线程池中读取客户端发来的数据,最终会调用ActivityManagerNative的onTransact方法。

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
    switch (code) {
        case START_ACTIVITY_TRANSACTION:{
            ...
            int result = startActivity(app, callingPackage, intent, resolvedType,
            ...
            return true;
        }
        ...
    }

    return super.onTransact(code, data, reply, flags);
}
复制代码

同时ActivityManagerService继承自ActivityManagerNative,因此onTransact方法的switch语句的START_ACTIVITY_TRANSACTION分支会调用AMS的startActivity。

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    @Override    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());
      }
}
复制代码

Android 8.0-Activity启动

Android8.0和7.0的Activity启动过程都会调用Instrumentation的execStartActivity方法,代码如下:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, String target,
        Intent intent, int requestCode, Bundle options) {
        ...
        try {
            ...
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
复制代码

在execStartActivity方法中通过ActivityManager的getService获取IActivityManager对象,并通过IActivityManager对象的startActivity方法通知AMS启动Activity。

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;
                }
            };
复制代码

IActivityManagerSingleto是一个单例类,在它的create方法中获取iBinder类型的AMS引用,接着通过AIDL,将AMS应用转换成IActivityManager类型的对象。相比于Android 7.0来说,这里去掉了ActivityManagerProxy这个代理类,由IActivityManager代替,这里的IActivityManager.aidl通过AIDL工具自动生成IActivityManager.java。

通过Android 7.0和Android 8.0的Activity启动流程可以得出Activity插件化的另一种方案:Hook IActivityManager,通过动态代理实现。

首先创建占坑Activity:

public class StubActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stub);
    }
}
复制代码

创建插件Activity:

public class TargetActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_target);
    }
}
复制代码

并在AndroidManifest.xml中注册占坑Activity:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.glh.haiproject01">

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="AllowBackup,GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".StubActivity" />
    </application>

</manifest>
复制代码

在AndroidManifest.xml中没有注册插件Activity,这时如果启动插件Activity会报错。

接着开始Hook IActivityManager,创建代理类IActivityManagerProxy:

public class IActivityManagerProxy implements InvocationHandler {

    private Object mActivityManager;

    public IActivityManagerProxy(Object activityManager){
        this.mActivityManager=activityManager;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("startActivity".equals(method.getName())){
            //拦截startActivity
            Intent intent=null;
            int index=0;
            for(int i=0,length=args.length;i<length;i++){
                if(args[i] instanceof Intent){
                    index=i;
                    break;
                }
            }
            //获取插件Activity的Intent
            intent= (Intent) args[index];
            //创建占坑Activity的Intent
            Intent subIntent=new Intent();
            subIntent.setClassName("com.glh.haiproject01","com.glh.haiproject01.StubActivity");
            //保存插件Activity的Intent
            subIntent.putExtra(HookHelper.REQUEST_TARGET_INTENT_NAME,intent);
            //替换为占坑Activity
            args[index]=subIntent;
        }
        return method.invoke(mActivityManager,args);
    }
}

复制代码

IActivityManagerProxy代理类的invoke非常简单,就是将插件Activity的Intent替换为占坑Activity的Intent,并保存插件Activity的Intent,方便后续还原。

private void hookIActivityManager(){
        Object defaultSingleton;
        if(Build.VERSION.SDK_INT==26){
            //Android 8.0
            defaultSingleton=getIActivityManagerSingleton();
        }else{
            defaultSingleton=getDefault();
        }
        try {
            Class<?> singletonClazz=Class.forName("android.util.Singleton");
            Field instanceField=singletonClazz.getDeclaredField("mInstance");
            instanceField.setAccessible(true);
            //获取defaultSingleton中IActivityManager类型的mInstance成员变量
            Object iActivityManager=instanceField.get(defaultSingleton);

            Class<?> iActivityManagerClazz=Class.forName("android.app.IActivityManager");
            Object proxy=Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class<?>[]{iActivityManagerClazz},new IActivityManagerProxy(iActivityManager));
            //替换为代理类IActivityManagerProxy
            instanceField.set(defaultSingleton,proxy);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private Object getIActivityManagerSingleton(){
        try {
            Class<?> activityManagerClazz=Class.forName("android.app.ActivityManager");
            Field field=activityManagerClazz.getDeclaredField("IActivityManagerSingleton");
            field.setAccessible(true);
            return field.get(null);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Object getDefault(){
        try {
            Class<?> activityManagerClazz=Class.forName("android.app.ActivityManagerNative");
            Field field=activityManagerClazz.getDeclaredField("gDefault");
            field.setAccessible(true);
            return field.get(null);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
复制代码

以上代码主要就是将Singleton的IActivityManager类型的成员变量mInstance替换成通过动态代理对象。当我们向AMS请求启动Activity时,会执行代理类IActivityManagerProxy的invoke方法进行狸猫换太子。

当AMS通过验证后需要还原插件Activity的Intent,在Android 8.0和Android 7.0(其他版本源码有可能不同)中,AMS通过Binder跨进程调用scheduleLaunchActivity,scheduleLaunchActivity方法在应用程序进程的Binder线程池中,通过mH发送LAUNCH_ACTIVITY消息(100)切换到主线程中创建并启动Activity。

mH的类型是ActivityThread中的内部类H,H继承自Handler并实现了handleMessage方法,在Handler源码中,有这么一段代码:

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

当mCallback不为null时会调用handleMessage方法,mCallback类型是Callback接口,因此我们可以Hook Callback,用自定的Callback替换Handler的mCallback。

代理Callback:

public class CallBackProxy implements Handler.Callback {

    private Handler mHandler;

    public CallBackProxy(Handler handler){
        this.mHandler=handler;
    }

    @Override
    public boolean handleMessage(Message msg) {
        if(msg.what==100){
            Object o=msg.obj;
            try {
                Field field=o.getClass().getDeclaredField("intent");
                field.setAccessible(true);
                //获取占坑Activity的Intent
                Intent intent= (Intent) field.get(o);
                //获取之前保存的插件Activity的Intent
                Intent targetIntent=intent.getParcelableExtra(HookHelper.REQUEST_TARGET_INTENT_NAME);
                //将占坑的Activity替换为插件Activity
                intent.setComponent(targetIntent.getComponent());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
        mHandler.handleMessage(msg);
        return true;
    }
}
复制代码

将Handler的mCallback替换为代理类CallBackProxy:

private  void hookHandler(){
        try {
            Class<?> activityThreadClazz=Class.forName("android.app.ActivityThread");
            Field currentActivityThreadField=activityThreadClazz.getDeclaredField("sCurrentActivityThread");
            currentActivityThreadField.setAccessible(true);
            Object currentActivityThread=currentActivityThreadField.get(null);

            Field handlerField=activityThreadClazz.getDeclaredField("mH");
            handlerField.setAccessible(true);
            Handler mH= (Handler) handlerField.get(currentActivityThread);

            Field callbackField=Handler.class.getDeclaredField("mCallback");
            callbackField.setAccessible(true);
            //Handler的mCallback替换为CallBackProxy
            callbackField.set(mH,new CallBackProxy(mH));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

复制代码

至此,Hook IActivityManager方案已经完成,在主界面中启动插件Activity:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_startActivity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MainActivity.this,TargetActivity.class);
                startActivity(intent);
            }
        });
    }
}
复制代码

运行效果:

Activity插件化原理第二种方案:Hook IActivityManager
Activity插件化原理第二种方案:Hook IActivityManager

以上所述就是小编给大家介绍的《Activity插件化原理第二种方案:Hook IActivityManager》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Numerical Recipes 3rd Edition

Numerical Recipes 3rd Edition

William H. Press、Saul A. Teukolsky、William T. Vetterling、Brian P. Flannery / Cambridge University Press / 2007-9-6 / GBP 64.99

Do you want easy access to the latest methods in scientific computing? This greatly expanded third edition of Numerical Recipes has it, with wider coverage than ever before, many new, expanded and upd......一起来看看 《Numerical Recipes 3rd Edition》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具