package com.lody.virtual.client; import android.os.Binder; import android.os.Build; import android.os.Process; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.client.ipc.VActivityManager; import com.lody.virtual.client.natives.NativeMethods; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.InstalledAppInfo; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; /** * VirtualApp Native Project */ public class NativeEngine { private static final String TAG = NativeEngine.class.getSimpleName(); private static Map<String, InstalledAppInfo> sDexOverrideMap; static { try { System.loadLibrary("va-native"); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } static { NativeMethods.init(); } public static void startDexOverride() { List<InstalledAppInfo> installedAppInfos = VirtualCore.get().getInstalledApps(0); sDexOverrideMap = new HashMap<>(installedAppInfos.size()); for (InstalledAppInfo info : installedAppInfos) { try { sDexOverrideMap.put(new File(info.apkPath).getCanonicalPath(), info); } catch (IOException e) { e.printStackTrace(); } } } public static String getRedirectedPath(String origPath) { try { return nativeGetRedirectedPath(origPath); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } return origPath; } public static String restoreRedirectedPath(String origPath) { try { return nativeRestoreRedirectedPath(origPath); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } return origPath; } public static void redirectDirectory(String origPath, String newPath) { if (!origPath.endsWith("/")) { origPath = origPath + "/"; } if (!newPath.endsWith("/")) { newPath = newPath + "/"; } try { nativeRedirect(origPath, newPath); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } public static void redirectFile(String origPath, String newPath) { if (origPath.endsWith("/")) { origPath = origPath.substring(0, origPath.length() - 1); } if (newPath.endsWith("/")) { newPath = newPath.substring(0, newPath.length() - 1); } try { nativeRedirect(origPath, newPath); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } public static void readOnly(String path) { try { nativeReadOnly(path); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } public static void hook() { try { int previewSdkInt = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? Build.VERSION.PREVIEW_SDK_INT : 0; nativeStartUniformer(Build.VERSION.SDK_INT, previewSdkInt); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } static void hookNative() { Method[] methods = {NativeMethods.gOpenDexFileNative, NativeMethods.gCameraNativeSetup, NativeMethods.gAudioRecordNativeCheckPermission}; try { nativeHookNative(methods, VirtualCore.get().getHostPkg(), VirtualRuntime.isArt(), Build.VERSION.SDK_INT, NativeMethods.gCameraMethodType); } catch (Throwable e) { VLog.e(TAG, VLog.getStackTraceString(e)); } } public static void onKillProcess(int pid, int signal) { VLog.e(TAG, "killProcess: pid = %d, signal = %d.", pid, signal); if (pid == android.os.Process.myPid()) { VLog.e(TAG, VLog.getStackTraceString(new Throwable())); } } public static int onGetCallingUid(int originUid) { int callingPid = Binder.getCallingPid(); if (callingPid == Process.myPid()) { return VClientImpl.get().getBaseVUid(); } if (callingPid == VirtualCore.get().getSystemPid()) { return Process.SYSTEM_UID; } int vuid = VActivityManager.get().getUidByPid(callingPid); if (vuid != -1) { return VUserHandle.getAppId(vuid); } VLog.d(TAG, "Unknown uid: " + callingPid); return VClientImpl.get().getBaseVUid(); } public static void onOpenDexFileNative(String[] params) { String dexOrJarPath = params[0]; String outputPath = params[1]; VLog.d(TAG, "DexOrJarPath = %s, OutputPath = %s.", dexOrJarPath, outputPath); try { String canonical = new File(dexOrJarPath).getCanonicalPath(); InstalledAppInfo info = sDexOverrideMap.get(canonical); if (info != null && !info.dependSystem) { outputPath = info.getOdexFile().getPath(); params[1] = outputPath; } } catch (IOException e) { e.printStackTrace(); } } private static native void nativeHookNative(Object method, String hostPackageName, boolean isArt, int apiLevel, int cameraMethodType); private static native void nativeMark(); private static native String nativeRestoreRedirectedPath(String redirectedPath); private static native String nativeGetRedirectedPath(String orgPath); private static native void nativeRedirect(String origPath, String newPath); private static native void nativeReadOnly(String path); private static native void nativeStartUniformer(int apiLevel, int previewApiLevel); public static int onGetUid(int uid) { return VClientImpl.get().getBaseVUid(); } }