上篇文章Android 插件化之——启动和停止插件Service讲解了启动插件service的演示,这篇文章,继续绑定插件service和解绑插件service的演示。和上篇启动插件service的原理类似,也是使用代理转发,通过Hook AMS,在AMS的bindService方法中,将要启动的插件service变换成代理service,这样绑定的其实就是代理service,然后将插件service的信息保存到Intent中,并将ServiceConnection对象作为key,插件Intent作为value,保存在一个HashMap的集合中(这样做是方便解绑时,通过unBind方法传入的ServiceConnection对象这个参数作为key从这个HashMap集合,拿到ServiceConnection对应的插件Service的Intent信息,然后,根据这个Intent信息,从插件services集合中,查找到对应的service对象)在代理service的onBind方法中,将实际的要绑定的插件service的信息从Intent中还原,然后创建插件service的实例对象,并调用插件service的attach方法,使绑定的插件service拥有上下文环境,接着调用插件service的onCreate方法,在调用插件service的onBind方法,并将插件service保存到插件services集合中。在解绑时,Hook AMS的 unbindService方法,在这个方法中通过传入的ServiceConnection参数,在保存了ServiceConnection的HashMap集合中,通过这个serviceConnection作为key,拿到相应的插件Service的Intent信息,然后,拿到插件service的Intent信息后,在通过这个Intent信息从插件services集合查找到对应的插件Service,然后调用插件Service的onUnbind方法,onDestroy方法。并将插件service从插件services集合中删除。在将保存了ServiceConnection的HashMap集合中将这个ServiceConnection相关的信息删除。
根据这个思路下面看看具体实现:
首先Hook AMS的bindService方法:
import android.content.Intent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import test.cn.example.com.androidskill.hook.service.ProxyService;
import test.cn.example.com.util.LogUtil;
public class IActivityManagerInvocationHandler implements InvocationHandler {
private final Object mActivityManager;
public IActivityManagerInvocationHandler(Object activityManager){
this.mActivityManager = activityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("startActivity")){
// ActivityManagerService类中的startActivity方法的10个参数
// startActivity(IApplicationThread caller, String callingPackage,
// Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
// int startFlags, ProfilerInfo profilerInfo, Bundle bOptions)
Intent intent = null;
int index = -1;
String packageName = "test.cn.example.com.androidskill";
String plugClassName = packageName+".hook.PlugActivity";
LogUtil.i("args.length "+args.length);
for (int i = 0; i < args.length; i++) {
// LogUtil.i(args[i]+"");
if(args[i] instanceof Intent){
Intent tempIntent = (Intent)args[i];
if(null !=tempIntent.getComponent() && plugClassName.equals(tempIntent.getComponent().getClassName())){
index = i;
break;
}
}
}
if(-1 !=index){
//实际要启动的intent
intent = (Intent) args[index];
//用占坑的BackUpActivity来通过AMS的检查
Intent backupIntent = new Intent();
//test.cn.example.com.androidskill.hook.BackUpActivity
backupIntent.setClassName(packageName,packageName+".hook.BackUpActivity");
backupIntent.putExtra(HookHelper.PLUG_INTENT,intent);
args[index] = backupIntent;
LogUtil.i("成功骗过了AMS");
}
}else if("bindService".equals(method.getName())){
// public int bindService(IApplicationThread caller, IBinder token, Intent service,
// String resolvedType, IServiceConnection connection, int flags, String callingPackage,
// int userId) throws TransactionTooLargeException {
//
// }
int index = -1;
for (int i = 0; i < args.length; i++) {
if(args[i] instanceof Intent){
index = i;
break;
}
}
Object serviceConnection = args[4];//这里取角标4,是因为AMS的bindService方法的第五个参数是IServiceConnection类型的。
if(null == serviceConnection){
throw new IllegalArgumentException("connection is null");
}
Intent rawIntent = (Intent) args[index];
String plugClassName = HookHelper.PACKAGENAME + ".hook.service.PlugService2";
String proxyClassName = HookHelper.PACKAGENAME + ".hook.service.ProxyService";
if(plugClassName.equals(rawIntent.getComponent().getClassName())){
Intent newIntent = new Intent();
newIntent.setClassName(HookHelper.PACKAGENAME, proxyClassName);
newIntent.putExtra(HookHelper.PLUG_INTENT,rawIntent);
//方法解绑时,查找相应的插件Service信息
ProxyService.mBindServices.put(serviceConnection,rawIntent);
args[index] = newIntent;
}
}else if("unbindService".equals(method.getName())){
// public boolean unbindService(IServiceConnection connection) {
//
// }
Object connection = args[0];
if(null == connection){
return false;
}
Intent rawIntent = ProxyService.mBindServices.get(connection);
if(null == rawIntent){
return false;
}
boolean result = ProxyService.unBindPlugService(rawIntent);
if(result){
ProxyService.mBindServices.remove(connection);
}
return result;
}
return method.invoke(mActivityManager,args);
}
}
这个类中,通过拦截AMS的bindService方法,将插件service的Intent信息,变为代理Service的Intent信息,并将IServiceConnection对象保存到一个mBindServices集合中。拦截的unbindService方法,是通过传入的IServiceConnection参数,从mBindServices集合中,查找到插件Service的实际Intent信息。然后通过这个实际的Intent信息,找到相应的插件Service,并调用插件Service的unBind,onDestroy方法,进行解绑和销毁。并将插件Service从mServices集合中删除,接着,在mBindServices集合中,删除和插件Service相关的IServiceConnection的信息。
下面看看ProxyService的具体实现:
import android.app.Application;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import androidx.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import test.cn.example.com.androidskill.hook.HookHelper;
import test.cn.example.com.androidskill.optimize.hotfix.FixDexUtils2;
import test.cn.example.com.util.LogUtil;
public class ProxyService extends Service {
public static HashMap mServices = new HashMap<>();
public static HashMap
完成上面两步后,在Application的子类的attachBaseContext方法中,调用HookHelper.hookAMS();
接着在Activity中,绑定和解绑插件service。
绑定插件Service的代码如下:
Intent intent_3 = new Intent();
Class> plugService2Clazz = null;
try {
plugService2Clazz = Class.forName(HookHelper.PACKAGENAME + ".hook.service.PlugService2");
intent_3.setClass(this,plugService2Clazz);
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtil.i("onServiceConnected " + name);
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtil.i("onServiceDisconnected " + name.getClassName());
}
};
bindService(intent_3, serviceConnection,Context.BIND_AUTO_CREATE);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
解绑插件Service的代码如下:
if(null != serviceConnection){
unbindService(serviceConnection);
}
绑定和解绑操作后,打印日志如下:
10-22 : ProxyService.java::27::onCreate-->>代理servcie onCreate
10-22 : ProxyService.java::90::onBind-->>代理onBind Intent { cmp=test.cn.example.com.androidskill/.hook.service.ProxyService (has extras) }
10-22 : PlugService2.java::16::onCreate-->>插件servcie222 onCreate
10-22 : PlugService2.java::29::onBind-->>插件onBind Intent { cmp=test.cn.example.com.androidskill/.hook.service.PlugService2 }
10-22 : PlugService2.java::35::onUnbind-->>插件onUnbind Intent { cmp=test.cn.example.com.androidskill/.hook.service.PlugService2 }
10-22 : PlugService2.java::42::onDestroy-->>插件service222 onDestroy