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);
    }
}