PluginProcessManager.java 源代码
package com.x8zs.morgoo.droidplugin.core;
import android.app.ActivityManager;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.text.TextUtils;
import com.efs.sdk.base.core.util.NetworkUtil;
import com.mbridge.msdk.playercommon.exoplayer2.util.MimeTypes;
import com.x8zs.morgoo.droidplugin.hook.HookFactory;
import com.x8zs.morgoo.droidplugin.pm.PluginManager;
import com.x8zs.morgoo.droidplugin.reflect.FieldUtils;
import com.x8zs.morgoo.droidplugin.reflect.MethodUtils;
import com.x8zs.morgoo.droidplugin.stub.ActivityStub;
import com.x8zs.morgoo.droidplugin.stub.ServiceStub;
import com.x8zs.morgoo.helper.Log;
import com.x8zs.morgoo.helper.compat.ActivityThreadCompat;
import com.x8zs.morgoo.helper.compat.CompatibilityInfoCompat;
import com.x8zs.morgoo.helper.compat.ProcessCompat;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class PluginProcessManager {
private static final String TAG = "GUNDAM";
private static String sCurrentProcessName;
private static List<String> sSkipService;
private static Object sGetCurrentProcessNameLock = new Object();
private static Map<String, ClassLoader> sPluginClassLoaderCache = new WeakHashMap(1);
private static Map<String, Object> sPluginLoadedApkCache = new WeakHashMap(1);
private static List<String> sProcessList = new ArrayList();
private static AtomicBoolean mExec = new AtomicBoolean(false);
private static Handler sHandle = new Handler(Looper.getMainLooper());
private static HashMap<String, Application> sApplicationsCache = new HashMap<>(2);
private static WeakHashMap<Integer, Context> mFakedContext = new WeakHashMap<>(1);
private static Object mServiceCache = null;
static {
ArrayList arrayList = new ArrayList();
sSkipService = arrayList;
arrayList.add("layout_inflater");
sSkipService.add("notification");
sSkipService.add("storage");
sSkipService.add("accessibility");
sSkipService.add(MimeTypes.BASE_TYPE_AUDIO);
sSkipService.add("clipboard");
sSkipService.add("media_router");
sSkipService.add(NetworkUtil.NETWORK_TYPE_WIFI);
sSkipService.add("captioning");
sSkipService.add("account");
sSkipService.add("activity");
sSkipService.add("wifiscanner");
sSkipService.add("rttmanager");
sSkipService.add("tv_input");
sSkipService.add("jobscheduler");
sSkipService.add("sensorhub");
sSkipService.add("servicediscovery");
}
public static void fakeSystemService(Context context, Context context2) {
if (!TextUtils.equals(context.getPackageName(), context2.getPackageName())) {
long currentTimeMillis = System.currentTimeMillis();
fakeSystemServiceInner(context, context2);
Log.i(TAG, "Fake SystemService for originContext=%s context=%s,cost %s ms", context2.getPackageName(), context2.getPackageName(), Long.valueOf(System.currentTimeMillis() - currentTimeMillis));
}
}
private static void fakeSystemServiceInner(Context context, Context context2) {
Object obj;
Object readField;
Object readField2;
try {
Context baseContext = getBaseContext(context2);
if (mFakedContext.containsValue(baseContext)) {
return;
}
Object obj2 = mServiceCache;
if (obj2 != null) {
FieldUtils.writeField(baseContext, "mServiceCache", obj2);
ContentResolver contentResolver = baseContext.getContentResolver();
if (contentResolver != null && (readField2 = FieldUtils.readField(contentResolver, "mContext")) != null) {
FieldUtils.writeField(readField2, "mServiceCache", mServiceCache);
}
if (!mFakedContext.containsValue(baseContext)) {
mFakedContext.put(Integer.valueOf(baseContext.hashCode()), baseContext);
return;
}
return;
}
try {
obj = FieldUtils.readStaticField(baseContext.getClass(), "SYSTEM_SERVICE_MAP");
} catch (Exception e6) {
Log.e(TAG, "readStaticField(SYSTEM_SERVICE_MAP) from %s fail", e6, baseContext.getClass());
obj = null;
}
if (obj == null) {
try {
obj = FieldUtils.readStaticField(Class.forName("android.app.SystemServiceRegistry"), "SYSTEM_SERVICE_FETCHERS");
} catch (Exception e7) {
Log.e(TAG, "readStaticField(SYSTEM_SERVICE_FETCHERS) from android.app.SystemServiceRegistry fail", e7, new Object[0]);
}
}
if (obj != null && (obj instanceof Map)) {
Map map = (Map) obj;
Context baseContext2 = getBaseContext(context);
Object readField3 = FieldUtils.readField(baseContext2, "mServiceCache");
if (readField3 instanceof List) {
((List) readField3).clear();
}
for (Object obj3 : map.keySet()) {
if (!sSkipService.contains(obj3)) {
Object obj4 = map.get(obj3);
try {
try {
obj4.getClass().getMethod("getService", baseContext.getClass()).invoke(obj4, baseContext2);
} catch (InvocationTargetException e8) {
if (e8.getCause() != null) {
Log.w(TAG, "Fake system service faile", e8, new Object[0]);
} else {
Log.w(TAG, "Fake system service faile", e8, new Object[0]);
}
}
} catch (Exception e9) {
Log.w(TAG, "Fake system service faile", e9, new Object[0]);
}
}
}
Object readField4 = FieldUtils.readField(baseContext2, "mServiceCache");
FieldUtils.writeField(baseContext, "mServiceCache", readField4);
ContentResolver contentResolver2 = baseContext.getContentResolver();
if (contentResolver2 != null && (readField = FieldUtils.readField(contentResolver2, "mContext")) != null) {
FieldUtils.writeField(readField, "mServiceCache", readField4);
}
}
if (!mFakedContext.containsValue(baseContext)) {
mFakedContext.put(Integer.valueOf(baseContext.hashCode()), baseContext);
}
} catch (Exception e10) {
Log.e(TAG, "fakeSystemServiceOldAPI", e10, new Object[0]);
}
}
private static Context getBaseContext(Context context) {
if (context instanceof ContextWrapper) {
return ((ContextWrapper) context).getBaseContext();
}
return context;
}
public static String getCurrentProcessName(Context context) {
if (context == null) {
return sCurrentProcessName;
}
synchronized (sGetCurrentProcessNameLock) {
if (sCurrentProcessName == null) {
List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = ((ActivityManager) context.getSystemService("activity")).getRunningAppProcesses();
if (runningAppProcesses == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
if (runningAppProcessInfo.pid == Process.myPid()) {
String str = runningAppProcessInfo.processName;
sCurrentProcessName = str;
return str;
}
}
}
return sCurrentProcessName;
}
}
public static ClassLoader getPluginClassLoader(String str) {
Application pluginContext;
if (sPluginClassLoaderCache.get(str) == null && (pluginContext = getPluginContext(str)) != null) {
sPluginClassLoaderCache.put(pluginContext.getPackageName(), pluginContext.getClassLoader());
}
return sPluginClassLoaderCache.get(str);
}
public static Application getPluginContext(String str) {
if (!sApplicationsCache.containsKey(str)) {
Object readField = FieldUtils.readField(ActivityThreadCompat.currentActivityThread(), "mAllApplications");
if (readField instanceof List) {
for (Object obj : (List) readField) {
if (obj instanceof Application) {
Application application = (Application) obj;
if (!sApplicationsCache.containsKey(application.getPackageName())) {
sApplicationsCache.put(application.getPackageName(), application);
}
}
}
}
}
return sApplicationsCache.get(str);
}
private static void initProcessList(Context context) {
String str;
String str2;
String str3;
try {
if (sProcessList.size() > 0) {
return;
}
sProcessList.add(context.getPackageName());
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 11);
ActivityInfo[] activityInfoArr = packageInfo.receivers;
if (activityInfoArr != null) {
for (ActivityInfo activityInfo : activityInfoArr) {
if (!sProcessList.contains(activityInfo.processName)) {
sProcessList.add(activityInfo.processName);
}
}
}
ProviderInfo[] providerInfoArr = packageInfo.providers;
if (providerInfoArr != null) {
for (ProviderInfo providerInfo : providerInfoArr) {
if (!sProcessList.contains(providerInfo.processName) && providerInfo.processName != null && (str3 = providerInfo.authority) != null && str3.indexOf(PluginManager.STUB_AUTHORITY_NAME) < 0) {
sProcessList.add(providerInfo.processName);
}
}
}
ServiceInfo[] serviceInfoArr = packageInfo.services;
if (serviceInfoArr != null) {
for (ServiceInfo serviceInfo : serviceInfoArr) {
if (!sProcessList.contains(serviceInfo.processName) && serviceInfo.processName != null && (str2 = serviceInfo.name) != null && str2.indexOf(ServiceStub.class.getSimpleName()) < 0) {
sProcessList.add(serviceInfo.processName);
}
}
}
ActivityInfo[] activityInfoArr2 = packageInfo.activities;
if (activityInfoArr2 != null) {
for (ActivityInfo activityInfo2 : activityInfoArr2) {
if (!sProcessList.contains(activityInfo2.processName) && activityInfo2.processName != null && (str = activityInfo2.name) != null && str.indexOf(ActivityStub.class.getSimpleName()) < 0) {
sProcessList.add(activityInfo2.processName);
}
}
}
} catch (PackageManager.NameNotFoundException unused) {
}
}
public static void installHook(Context context) {
HookFactory.getInstance().installHook(context, (ClassLoader) null);
}
public static final boolean isPluginProcess(Context context) {
if (TextUtils.equals(getCurrentProcessName(context), context.getPackageName())) {
return false;
}
initProcessList(context);
return !sProcessList.contains(r0);
}
public static void preLoadApk(Context context, ComponentInfo componentInfo) {
boolean z6;
PluginClassLoader pluginClassLoader;
if (componentInfo == null && context == null) {
return;
}
if (componentInfo != null && getPluginContext(componentInfo.packageName) != null) {
return;
}
synchronized (sPluginLoadedApkCache) {
Object currentActivityThread = ActivityThreadCompat.currentActivityThread();
z6 = false;
if (currentActivityThread != null) {
Object invokeMethod = MethodUtils.invokeMethod(FieldUtils.readField(currentActivityThread, "mPackages"), "containsKey", componentInfo.packageName);
if ((invokeMethod instanceof Boolean) && !((Boolean) invokeMethod).booleanValue()) {
Object invokeMethod2 = MethodUtils.invokeMethod(currentActivityThread, "getPackageInfoNoCheck", componentInfo.applicationInfo, CompatibilityInfoCompat.DEFAULT_COMPATIBILITY_INFO());
sPluginLoadedApkCache.put(componentInfo.packageName, invokeMethod2);
String pluginDalvikCacheDir = PluginDirHelper.getPluginDalvikCacheDir(context, componentInfo.packageName);
String pluginNativeLibraryDir = PluginDirHelper.getPluginNativeLibraryDir(context, componentInfo.packageName);
String str = componentInfo.applicationInfo.publicSourceDir;
if (TextUtils.isEmpty(str)) {
componentInfo.applicationInfo.publicSourceDir = PluginDirHelper.getPluginApkFile(context, componentInfo.packageName);
str = componentInfo.applicationInfo.publicSourceDir;
}
if (str != null) {
try {
pluginClassLoader = new PluginClassLoader(str, pluginDalvikCacheDir, pluginNativeLibraryDir, ClassLoader.getSystemClassLoader());
} catch (Exception unused) {
pluginClassLoader = null;
}
if (pluginClassLoader == null) {
PluginDirHelper.cleanOptimizedDirectory(pluginDalvikCacheDir);
pluginClassLoader = new PluginClassLoader(str, pluginDalvikCacheDir, pluginNativeLibraryDir, ClassLoader.getSystemClassLoader());
}
synchronized (invokeMethod2) {
FieldUtils.writeDeclaredField(invokeMethod2, "mClassLoader", pluginClassLoader);
}
sPluginClassLoaderCache.put(componentInfo.packageName, pluginClassLoader);
Thread.currentThread().setContextClassLoader(pluginClassLoader);
z6 = true;
}
ProcessCompat.setArgV0(componentInfo.processName);
}
}
}
if (z6) {
preMakeApplication(context, componentInfo);
}
}
private static void preMakeApplication(Context context, ComponentInfo componentInfo) {
try {
final Object obj = sPluginLoadedApkCache.get(componentInfo.packageName);
if (obj == null || FieldUtils.readField(obj, "mApplication") != null) {
return;
}
if (Looper.getMainLooper() != Looper.myLooper()) {
final Object obj2 = new Object();
mExec.set(false);
sHandle.post(new Runnable() {
@Override
public void run() {
try {
try {
MethodUtils.invokeMethod(obj, "makeApplication", Boolean.FALSE, ActivityThreadCompat.getInstrumentation());
PluginProcessManager.mExec.set(true);
synchronized (obj2) {
obj2.notifyAll();
}
} catch (Exception e6) {
Log.e(PluginProcessManager.TAG, "preMakeApplication FAIL", e6, new Object[0]);
PluginProcessManager.mExec.set(true);
synchronized (obj2) {
obj2.notifyAll();
}
}
} catch (Throwable th) {
PluginProcessManager.mExec.set(true);
synchronized (obj2) {
obj2.notifyAll();
throw th;
}
}
}
});
if (!mExec.get()) {
synchronized (obj2) {
try {
obj2.wait();
} catch (InterruptedException unused) {
}
}
return;
}
return;
}
MethodUtils.invokeMethod(obj, "makeApplication", Boolean.FALSE, ActivityThreadCompat.getInstrumentation());
} catch (Exception e6) {
Log.e(TAG, "preMakeApplication FAIL", e6, new Object[0]);
}
}
public static void registerStaticReceiver(Context context, ApplicationInfo applicationInfo, ClassLoader classLoader) {
String str;
List<ActivityInfo> receivers = PluginManager.getInstance().getReceivers(applicationInfo.packageName, 0);
if (receivers != null && receivers.size() > 0) {
try {
str = PluginManager.getInstance().getProcessNameByPid(Process.myPid());
} catch (Exception unused) {
str = null;
}
for (ActivityInfo activityInfo : receivers) {
if (TextUtils.equals(activityInfo.processName, str)) {
try {
Iterator<IntentFilter> it = PluginManager.getInstance().getReceiverIntentFilter(activityInfo).iterator();
while (it.hasNext()) {
context.registerReceiver((BroadcastReceiver) classLoader.loadClass(activityInfo.name).newInstance(), it.next());
}
} catch (Exception e6) {
Log.e(TAG, "registerStaticReceiver error=%s", e6, activityInfo.name);
}
}
}
}
}
public static void setHookEnable(boolean z6) {
HookFactory.getInstance().setHookEnable(z6);
}
public static void setHookEnable(boolean z6, boolean z7) {
HookFactory.getInstance().setHookEnable(z6, z7);
}
}