/* ** DroidPlugin Project ** ** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com> ** ** This file is part of DroidPlugin. ** ** DroidPlugin is free software: you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation, either ** version 3 of the License, or (at your option) any later version. ** ** DroidPlugin is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with DroidPlugin. If not, see <http://www.gnu.org/licenses/lgpl.txt> ** **/ package com.morgoo.droidplugin.hook.handle; import android.annotation.TargetApi; import android.app.Activity; import android.app.Application; import android.app.Instrumentation; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.text.TextUtils; import com.morgoo.droidplugin.am.RunningActivities; import com.morgoo.droidplugin.core.Env; import com.morgoo.droidplugin.core.PluginProcessManager; import com.morgoo.droidplugin.hook.HookFactory; import com.morgoo.droidplugin.hook.binder.IWindowManagerBinderHook; import com.morgoo.droidplugin.hook.proxy.IPackageManagerHook; import com.morgoo.droidplugin.pm.PluginManager; import com.morgoo.droidplugin.reflect.FieldUtils; import com.morgoo.helper.Log; import java.lang.reflect.Field; /** * Created by Andy Zhang(zhangyong232@gmail.com) on 2014/12/5. */ public class PluginInstrumentation extends Instrumentation { protected static final String TAG = PluginInstrumentation.class.getSimpleName(); protected Instrumentation mTarget; private final Context mHostContext; private boolean enable = true; public void setEnable(boolean enable) { this.enable = enable; this.enable = true; } public PluginInstrumentation(Context hostContext, Instrumentation target) { mTarget = target; mHostContext = hostContext; } @Override public void callActivityOnCreate(Activity activity, Bundle icicle) { if (enable) { IWindowManagerBinderHook.fixWindowManagerHook(activity); IPackageManagerHook.fixContextPackageManager(activity); try { PluginProcessManager.fakeSystemService(mHostContext, activity); } catch (Exception e) { Log.e(TAG, "callActivityOnCreate:fakeSystemService", e); } try { onActivityCreated(activity); } catch (RemoteException e) { Log.e(TAG, "callActivityOnCreate:onActivityCreated", e); } try { fixBaseContextImplOpsPackage(activity.getBaseContext()); } catch (Exception e) { Log.e(TAG, "callActivityOnCreate:fixBaseContextImplOpsPackage", e); } try { fixBaseContextImplContentResolverOpsPackage(activity.getBaseContext()); } catch (Exception e) { Log.e(TAG, "callActivityOnCreate:fixBaseContextImplContentResolverOpsPackage", e); } } if (mTarget != null) { mTarget.callActivityOnCreate(activity, icicle); } else { super.callActivityOnCreate(activity, icicle); } } private void fixBaseContextImplOpsPackage(Context context) throws IllegalAccessException { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && context != null && !TextUtils.equals(context.getPackageName(), mHostContext.getPackageName())) { Context baseContext = context; Class clazz = baseContext.getClass(); Field mOpPackageName = FieldUtils.getDeclaredField(clazz, "mOpPackageName", true); if (mOpPackageName != null) { Object valueObj = mOpPackageName.get(baseContext); if (valueObj instanceof String) { String opPackageName = ((String) valueObj); if (!TextUtils.equals(opPackageName, mHostContext.getPackageName())) { mOpPackageName.set(baseContext, mHostContext.getPackageName()); Log.i(TAG, "fixBaseContextImplOpsPackage OK!Context=%s,", baseContext); } } } } } private void fixBaseContextImplContentResolverOpsPackage(Context context) throws IllegalAccessException { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1 && context != null && !TextUtils.equals(context.getPackageName(), mHostContext.getPackageName())) { Context baseContext = context; Class clazz = baseContext.getClass(); Field mContentResolver = FieldUtils.getDeclaredField(clazz, "mContentResolver", true); if (mContentResolver != null) { Object valueObj = mContentResolver.get(baseContext); if (valueObj instanceof ContentResolver) { ContentResolver contentResolver = ((ContentResolver) valueObj); Field mPackageName = FieldUtils.getDeclaredField(ContentResolver.class, "mPackageName", true); Object mPackageNameValueObj = mPackageName.get(contentResolver); if (mPackageNameValueObj != null && mPackageNameValueObj instanceof String) { String packageName = ((String) mPackageNameValueObj); if (!TextUtils.equals(packageName, mHostContext.getPackageName())) { mPackageName.set(contentResolver, mHostContext.getPackageName()); Log.i(TAG, "fixBaseContextImplContentResolverOpsPackage OK!Context=%s,contentResolver=%s", baseContext, contentResolver); } } } } } } private void onActivityCreated(Activity activity) throws RemoteException { try { Intent targetIntent = activity.getIntent(); if (targetIntent != null) { ActivityInfo targetInfo = targetIntent.getParcelableExtra(Env.EXTRA_TARGET_INFO); ActivityInfo stubInfo = targetIntent.getParcelableExtra(Env.EXTRA_STUB_INFO); if (targetInfo != null && stubInfo != null) { RunningActivities.onActivtyCreate(activity, targetInfo, stubInfo); if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED && targetInfo.screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { activity.setRequestedOrientation(targetInfo.screenOrientation); } PluginManager.getInstance().onActivityCreated(stubInfo, targetInfo); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { fixTaskDescription(activity, targetInfo); } } } } catch (Exception e) { Log.i(TAG, "onActivityCreated fail", e); } } private void onActivityOnNewIntent(Activity activity, Intent intent) throws RemoteException { // try { Intent targetIntent = activity.getIntent(); if (targetIntent != null) { ActivityInfo targetInfo = targetIntent.getParcelableExtra(Env.EXTRA_TARGET_INFO); ActivityInfo stubInfo = targetIntent.getParcelableExtra(Env.EXTRA_STUB_INFO); if (targetInfo != null && stubInfo != null) { RunningActivities.onActivtyOnNewIntent(activity, targetInfo, stubInfo, intent); PluginManager.getInstance().onActivtyOnNewIntent(stubInfo, targetInfo, intent); } } } catch (Exception e) { Log.i(TAG, "onActivityCreated fail", e); } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void fixTaskDescription(Activity activity, ActivityInfo targetInfo) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { PackageManager pm = mHostContext.getPackageManager(); String lablel = String.valueOf(targetInfo.loadLabel(pm)); Drawable icon = targetInfo.loadIcon(pm); Bitmap bitmap = null; if (icon instanceof BitmapDrawable) { bitmap = ((BitmapDrawable) icon).getBitmap(); } if (bitmap != null) { activity.setTaskDescription(new android.app.ActivityManager.TaskDescription(lablel, bitmap)); } else { activity.setTaskDescription(new android.app.ActivityManager.TaskDescription(lablel)); } } } catch (Throwable e) { Log.w(TAG, "fixTaskDescription fail", e); } } private void onActivityDestory(Activity activity) throws RemoteException { Intent targetIntent = activity.getIntent(); if (targetIntent != null) { ActivityInfo targetInfo = targetIntent.getParcelableExtra(Env.EXTRA_TARGET_INFO); ActivityInfo stubInfo = targetIntent.getParcelableExtra(Env.EXTRA_STUB_INFO); if (targetInfo != null && stubInfo != null) { PluginManager.getInstance().onActivityDestory(stubInfo, targetInfo); } } } @Override public void callActivityOnDestroy(Activity activity) { if (mTarget != null) { mTarget.callActivityOnDestroy(activity); } else { super.callActivityOnDestroy(activity); } RunningActivities.onActivtyDestory(activity); if (enable) { try { onActivityDestory(activity); } catch (RemoteException e) { Log.e(TAG, "callActivityOnDestroy:onActivityDestory", e); } } } @Override public void callApplicationOnCreate(Application app) { if (enable) { IPackageManagerHook.fixContextPackageManager(app); try { PluginProcessManager.fakeSystemService(mHostContext, app); } catch (Exception e) { Log.e(TAG, "fakeSystemService", e); } try { fixBaseContextImplOpsPackage(app.getBaseContext()); } catch (Exception e) { Log.e(TAG, "callApplicationOnCreate:fixBaseContextImplOpsPackage", e); } try { fixBaseContextImplContentResolverOpsPackage(app.getBaseContext()); } catch (Exception e) { Log.e(TAG, "callActivityOnCreate:fixBaseContextImplContentResolverOpsPackage", e); } } try { HookFactory.getInstance().onCallApplicationOnCreate(mHostContext, app); } catch (Exception e) { Log.e(TAG, "onCallApplicationOnCreate", e); } if (mTarget != null) { mTarget.callApplicationOnCreate(app); } else { super.callApplicationOnCreate(app); } if (enable) { try { PluginProcessManager.registerStaticReceiver(app, app.getApplicationInfo(), app.getClassLoader()); } catch (Exception e) { Log.e(TAG, "registerStaticReceiver", e); } } } @Override public void callActivityOnNewIntent(Activity activity, Intent intent) { // if (activity != null && intent != null) { // intent.setClassName(activity.getPackageName(), activity.getClass().getName()); // } try { Intent newIntent = intent.getParcelableExtra(Env.EXTRA_TARGET_INTENT); if (newIntent != null) { intent = newIntent; } } catch (Throwable e) { Log.e(TAG, "callActivityOnNewIntent:read EXTRA_TARGET_INTENT", e); } if (enable) { try { onActivityOnNewIntent(activity, intent); } catch (RemoteException e) { Log.e(TAG, "callActivityOnNewIntent:onActivityOnNewIntent", e); } } if (mTarget != null) { mTarget.callActivityOnNewIntent(activity, intent); } else { super.callActivityOnNewIntent(activity, intent); } } }