原因:
当插件化hook跳转Activity成功,还需要去检查activity信息是否存在。如果不处理就会报错。
10-25 19:32:30.867 8754 8754 E AndroidRuntime: Caused by: java.lang.IllegalArgumentException: android.content.pm.PackageManager$NameNotFoundException: ComponentInfo{me.linjw.plugindemo/me.linjw.plugindemo.HideActivity}
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.support.v4.app.NavUtils.getParentActivityName(NavUtils.java:285)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.support.v7.app.AppCompatDelegateImplV9.onCreate(AppCompatDelegateImplV9.java:158)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.support.v7.app.AppCompatDelegateImplV14.onCreate(AppCompatDelegateImplV14.java:58)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:72)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at com.cvte.tv.speech.TestActivity.onCreate(TestActivity.java:14)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:6664)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
10-25 19:32:30.867 8754 8754 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
分析:
context.getPackageManager();因为这个packageManager获取不到,因为它是插件,所以要伪造一个。
public static String getParentActivityName(Activity sourceActivity) {
try {
return getParentActivityName(sourceActivity, sourceActivity.getComponentName());
} catch (NameNotFoundException e) {
// Component name of supplied activity does not exist...?
throw new IllegalArgumentException(e);
}
}
@Nullable
public static String getParentActivityName(Context context, ComponentName componentName)
throws NameNotFoundException {
PackageManager pm = context.getPackageManager();
ActivityInfo info = pm.getActivityInfo(componentName, PackageManager.GET_META_DATA);
String parentActivity = IMPL.getParentActivityName(context, info);
return parentActivity;
}
class ContextImpl extends Context {
...
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
...
}
public final class ActivityThread {
...
static volatile IPackageManager sPackageManager;
...
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
...
}
所以就从sPackageManager下手处理。
private static void hookPackageManager() throws Exception {
try {
// 兼容AppCompatActivity报错问题
Class<?> forName = Class.forName("android.app.ActivityThread");
Field field = forName.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object activityThread = field.get(null);
Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
Object iPackageManager = getPackageManager.invoke(activityThread);
Class<?> iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{iPackageManagerIntercept}, new MockClass3(iPackageManager));
// 获取 sPackageManager 属性
Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager");
iPackageManagerField.setAccessible(true);
iPackageManagerField.set(activityThread, proxy);
}catch (Exception e){
Log.e(TAG,"onHookIPackageManager:"+e.toString());
}
}
public class MockClass3 implements InvocationHandler {
private static final String TAG = "MockClass3";
public Object iPackageManager;
public MockClass3(Object iPackageManager) {
this.iPackageManager = iPackageManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e(TAG, "invoke: "+method.getName());
if ("getActivityInfo".equals(method.getName())){
for (int i=0;i<args.length;i++){
if (args[i] instanceof ComponentName){
ComponentName componentName = new ComponentName(UPFApplication.getContext().getPackageName(),
StubActivity.class.getName());
args[i] = componentName;
}
}
}
return method.invoke(iPackageManager,args);
}
}