diff --git a/VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyVirtualInitializer.java b/VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyVirtualInitializer.java index 8c8541486..1afe1a80b 100644 --- a/VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyVirtualInitializer.java +++ b/VirtualApp/app/src/aosp/java/io/virtualapp/delegate/MyVirtualInitializer.java @@ -3,6 +3,9 @@ import android.app.Application; import com.lody.virtual.client.core.VirtualCore; +import com.lody.virtual.client.hook.proxies.view.AutoFillManagerStub; +import com.lody.virtual.helper.compat.BuildCompat; +import com.lody.virtual.helper.utils.VLog; import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.analytics.Analytics; import com.microsoft.appcenter.crashes.Crashes; @@ -12,6 +15,9 @@ * @date 2019/2/25. */ public class MyVirtualInitializer extends BaseVirtualInitializer { + + static final String TAG = "MyVirtualInitializer"; + public MyVirtualInitializer(Application application, VirtualCore core) { super(application, core); } @@ -34,5 +40,21 @@ public void onVirtualProcess() { // Override virtualCore.setCrashHandler(new MyCrashHandler()); + + + if (BuildCompat.isOreo()) { + // Android 13以上的版本在attachBaseContext里注入这个对象会报错,所以挪到这里来 + try { + new AutoFillManagerStub().inject(); + } catch (Throwable e) { + VLog.w(TAG, "AutoFillManagerStub inject error",e ); + } + } + + } + + @Override + public void onChildProcess() { + super.onChildProcess(); } } diff --git a/VirtualApp/lib/src/main/java/android/app/ClientTransactionHandler.java b/VirtualApp/lib/src/main/java/android/app/ClientTransactionHandler.java index 7047e547e..d8e70133b 100644 --- a/VirtualApp/lib/src/main/java/android/app/ClientTransactionHandler.java +++ b/VirtualApp/lib/src/main/java/android/app/ClientTransactionHandler.java @@ -172,6 +172,11 @@ public abstract void handleAttachSplashScreenView(ActivityThread.ActivityClientR /** Perform activity launch. */ public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent); + + // Android 13 + public abstract Activity handleLaunchActivity( ActivityThread.ActivityClientRecord r, + PendingTransactionActions pendingActions, int deviceId, Intent customIntent); + /** Perform activity start. */ public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions); @@ -184,6 +189,10 @@ public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r, // Android 11 public abstract void handleStartActivity(IBinder binder, PendingTransactionActions pendingActions); + + // Android 14 + public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai); + /** Get package info. */ public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo); diff --git a/VirtualApp/lib/src/main/java/android/app/TransactionHandlerProxy.java b/VirtualApp/lib/src/main/java/android/app/TransactionHandlerProxy.java index 51a592528..469c3719d 100644 --- a/VirtualApp/lib/src/main/java/android/app/TransactionHandlerProxy.java +++ b/VirtualApp/lib/src/main/java/android/app/TransactionHandlerProxy.java @@ -9,6 +9,7 @@ import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.os.Build; import android.os.IBinder; import android.os.Parcelable; import android.util.Log; @@ -49,6 +50,11 @@ TransactionExecutor getTransactionExecutor() { return originalHandler.getTransactionExecutor(); } + /** Get package info. */ + public LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) { + return originalHandler.getPackageInfoNoCheck(ai); + } + @Override void sendMessage(int what, Object obj) { originalHandler.sendMessage(what, obj); @@ -194,8 +200,16 @@ public void handleWindowVisibility(IBinder token, boolean show) { originalHandler.handleWindowVisibility(token, show); } + + public Activity handleLaunchActivity( ActivityThread.ActivityClientRecord r, + PendingTransactionActions pendingActions, Intent customIntent) { + return handleLaunchActivity(r, pendingActions, 0, customIntent); + } + + + // Android 13 @Override - public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { + public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, int deviceId, Intent customIntent) { Intent stubIntent = mirror.android.app.ActivityThread.ActivityClientRecord.intent.get(r); StubActivityRecord saveInstance = new StubActivityRecord(stubIntent); @@ -216,13 +230,13 @@ public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionA VActivityManager.get().processRestarted(info.packageName, info.processName, saveInstance.userId); // getH().sendMessageAtFrontOfQueue(Message.obtain(msg)); Log.i(TAG, "restart process, return"); - return handleLaunchActivity(r, pendingActions, customIntent); + return handleLaunchActivity(r, pendingActions, deviceId, customIntent); } if (!VClientImpl.get().isBound()) { VClientImpl.get().bindApplicationForActivity(info.packageName, info.processName, intent); // getH().sendMessageAtFrontOfQueue(Message.obtain(msg)); Log.i(TAG, "rebound application, return"); - return handleLaunchActivity(r, pendingActions, customIntent); + return handleLaunchActivity(r, pendingActions, deviceId, customIntent); } int taskId = IActivityManager.getTaskForActivity.call( ActivityManagerNative.getDefault.call(), @@ -240,7 +254,12 @@ public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionA mirror.android.app.ActivityThread.ActivityClientRecord.intent.set(r, intent); mirror.android.app.ActivityThread.ActivityClientRecord.activityInfo.set(r, info); - return originalHandler.handleLaunchActivity(r, pendingActions, customIntent); + if (Build.VERSION.SDK_INT >= 34) { + return originalHandler.handleLaunchActivity(r, pendingActions, deviceId, customIntent); + } else { + return originalHandler.handleLaunchActivity(r, pendingActions, customIntent); + } + } @Override diff --git a/VirtualApp/lib/src/main/java/android/content/pm/SigningDetails.java b/VirtualApp/lib/src/main/java/android/content/pm/SigningDetails.java new file mode 100644 index 000000000..510136c7c --- /dev/null +++ b/VirtualApp/lib/src/main/java/android/content/pm/SigningDetails.java @@ -0,0 +1,4 @@ +package android.content.pm; + +public class SigningDetails { +} diff --git a/VirtualApp/lib/src/main/java/android/os/UserHandle.java b/VirtualApp/lib/src/main/java/android/os/UserHandle.java new file mode 100644 index 000000000..b054a71e9 --- /dev/null +++ b/VirtualApp/lib/src/main/java/android/os/UserHandle.java @@ -0,0 +1,4 @@ +package android.os; + +public class UserHandle { +} diff --git a/VirtualApp/lib/src/main/java/android/os/storage/StorageVolume.java b/VirtualApp/lib/src/main/java/android/os/storage/StorageVolume.java new file mode 100644 index 000000000..d25571400 --- /dev/null +++ b/VirtualApp/lib/src/main/java/android/os/storage/StorageVolume.java @@ -0,0 +1,4 @@ +package android.os.storage; + +public class StorageVolume { +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java index 5afffe4a1..c2a0ea6c4 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/VClientImpl.java @@ -255,19 +255,23 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond null ); AppBindData data = new AppBindData(); + InstalledAppInfo info = VirtualCore.get().getInstalledAppInfo(packageName, 0); if (info == null) { new Exception("App not exist!").printStackTrace(); Process.killProcess(0); System.exit(0); } + VLog.d(TAG, "bindApplicationNoCheck getInstalledAppInfo:" + info); data.appInfo = VPackageManager.get().getApplicationInfo(packageName, 0, getUserId(vuid)); data.processName = processName; data.appInfo.processName = processName; data.providers = VPackageManager.get().queryContentProviders(processName, getVUid(), PackageManager.GET_META_DATA); VLog.i(TAG, String.format("Binding application %s, (%s)", data.appInfo.packageName, data.processName)); mBoundApplication = data; + VirtualRuntime.setupRuntime(data.processName, data.appInfo); + int targetSdkVersion = data.appInfo.targetSdkVersion; if (targetSdkVersion < Build.VERSION_CODES.GINGERBREAD) { StrictMode.ThreadPolicy newPolicy = new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy()).permitNetwork().build(); @@ -282,22 +286,23 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond NativeEngine.launchEngine(); Object mainThread = VirtualCore.mainThread(); NativeEngine.startDexOverride(); - Context context = createPackageContext(data.appInfo.packageName); + + Context appContext = createPackageContext(data.appInfo.packageName); try { // anti-virus, fuck ESET-NOD32: a variant of Android/AdDisplay.AdLock.AL potentially unwanted // we can make direct call... use reflect to bypass. // System.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath()); System.class.getDeclaredMethod("setProperty", String.class, String.class) - .invoke(null, "java.io.tmpdir", context.getCacheDir().getAbsolutePath()); + .invoke(null, "java.io.tmpdir", appContext.getCacheDir().getAbsolutePath()); } catch (Throwable ignored) { VLog.e(TAG, "set tmp dir error:", ignored); } File codeCacheDir; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - codeCacheDir = context.getCodeCacheDir(); + codeCacheDir = appContext.getCodeCacheDir(); } else { - codeCacheDir = context.getCacheDir(); + codeCacheDir = appContext.getCacheDir(); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { if (HardwareRenderer.setupDiskCache != null) { @@ -318,7 +323,8 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond } } Object boundApp = fixBoundApp(mBoundApplication); - mBoundApplication.info = ContextImpl.mPackageInfo.get(context); + mBoundApplication.info = ContextImpl.mPackageInfo.get(appContext); + mirror.android.app.ActivityThread.AppBindData.info.set(boundApp, data.info); VMRuntime.setTargetSdkVersion.call(VMRuntime.getRuntime.call(), data.appInfo.targetSdkVersion); @@ -336,23 +342,37 @@ private void bindApplicationNoCheck(String packageName, String processName, Cond boolean enableXposed = VirtualCore.get().isXposedEnabled(); if (enableXposed) { VLog.i(TAG, "Xposed is enabled."); - ClassLoader originClassLoader = context.getClassLoader(); - ExposedBridge.initOnce(context, data.appInfo, originClassLoader); - List modules = VirtualCore.get().getInstalledApps(0); - for (InstalledAppInfo module : modules) { - ExposedBridge.loadModule(module.apkPath, module.getOdexFile().getParent(), module.libPath, - data.appInfo, originClassLoader); + + // 内部报错:java.lang.ClassNotFoundException: Didn't find class "androidx.core.app.CoreComponentFactory" on path: DexPathList[[zip file "/data/user/0/io.va.exposed64/virtual/data/app/com.laolaiwangtech/base.apk"],nativeLibraryDirectories=[/data/user/0/io.va.exposed64/virtual/data/app/com.laolaiwangtech/lib, /data/user/0/io.va.exposed64/virtual/data/app/com.laolaiwangtech/base.apk!/lib/arm64-v8a, /system/lib64, /product_h/lib64, /system_ext/lib64]] + + ClassLoader originClassLoader = null; + try { + originClassLoader = appContext.getClassLoader(); + } catch (Exception e) { + VLog.w(TAG, "appContext.getClassLoader() error", e); + } + if (originClassLoader !=null) { + ExposedBridge.initOnce(appContext, data.appInfo, originClassLoader); + + List modules = VirtualCore.get().getInstalledApps(0); + for (InstalledAppInfo module : modules) { + ExposedBridge.loadModule(module.apkPath, module.getOdexFile().getParent(), module.libPath, + data.appInfo, originClassLoader); + } } } else { VLog.w(TAG, "Xposed is disable.."); } + + ClassLoader cl = LoadedApk.getClassLoader.call(data.info); if (BuildCompat.isS()) { ClassLoader parent = cl.getParent(); Reflect.on(cl).set("parent", new DelegateLastClassLoader("/system/framework/android.test.base.jar", parent)); } + if (Build.VERSION.SDK_INT >= 30) ApplicationConfig.setDefaultInstance.call(new Object[] { null }); mInitialApplication = LoadedApk.makeApplication.call(data.info, false, null); @@ -509,7 +529,7 @@ private void setupVirtualStorage(ApplicationInfo info, int userId) { } HashSet storageRoots = getMountPoints(); - storageRoots.add(Environment.getExternalStorageDirectory().getAbsolutePath()); + storageRoots.add(VEnvironment.getExternalStorageDirectory().getAbsolutePath()); Set whiteList = new HashSet<>(); whiteList.add(Environment.DIRECTORY_PODCASTS); @@ -531,7 +551,7 @@ private void setupVirtualStorage(ApplicationInfo info, int userId) { // ensure virtual storage white directory exists. for (String whiteDir : whiteList) { - File originalDir = new File(Environment.getExternalStorageDirectory(), whiteDir); + File originalDir = new File(VEnvironment.getExternalStorageDirectory(), whiteDir); File virtualDir = new File(vsDir, whiteDir); if (!originalDir.exists()) { continue; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java index cbed63796..99d533ac4 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/InvocationStubManager.java @@ -1,5 +1,13 @@ package com.lody.virtual.client.core; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; +import static android.os.Build.VERSION_CODES.KITKAT; +import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; +import static android.os.Build.VERSION_CODES.M; +import static android.os.Build.VERSION_CODES.N; + import android.os.Build; import com.lody.virtual.client.hook.base.MethodInvocationProxy; @@ -62,14 +70,6 @@ import java.util.HashMap; import java.util.Map; -import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; -import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; -import static android.os.Build.VERSION_CODES.KITKAT; -import static android.os.Build.VERSION_CODES.LOLLIPOP; -import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; -import static android.os.Build.VERSION_CODES.M; -import static android.os.Build.VERSION_CODES.N; - /** * @author Lody * @@ -111,6 +111,7 @@ public void init() throws Throwable { injectInternal(); sInit = true; + } private void injectInternal() throws Throwable { @@ -192,9 +193,12 @@ private void injectInternal() throws Throwable { addInjector(new BatteryStatsStub()); } - if (BuildCompat.isOreo()) { - addInjector(new AutoFillManagerStub()); - } + + // After Android 13, this will throw java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.ContentResolver android.app.Application.getContentResolver()' on a null object reference + // move in application onCreate +// if (BuildCompat.isOreo()) { +// addInjector(new AutoFillManagerStub()); +// } if (BuildCompat.isQ()) { addInjector(new ActivityTaskManagerStub()); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java index 96fa87142..7448c64b4 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/env/SpecialComponentList.java @@ -7,6 +7,7 @@ import android.os.Build; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -124,9 +125,18 @@ public static void addBlackAction(String action) { ACTION_BLACK_LIST.add(action); } + private static List toList(Object actionsObj) { + List actions = new ArrayList<>(); + if (actionsObj instanceof Collection) { + actions.addAll((Collection) actionsObj); + } + return actions; + } + public static void protectIntentFilter(IntentFilter filter) { if (filter != null) { - List actions = mirror.android.content.IntentFilter.mActions.get(filter); + // 13以后这里返回的是set, 做个兼容 + List actions = toList(mirror.android.content.IntentFilter.mActions.get(filter)); ListIterator iterator = actions.listIterator(); while (iterator.hasNext()) { String action = iterator.next(); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MethodProxies.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MethodProxies.java index 608fff712..07e143a5f 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MethodProxies.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MethodProxies.java @@ -1,12 +1,20 @@ package com.lody.virtual.client.hook.proxies.mount; import android.os.Build; +import android.os.Environment; +import android.util.Log; +import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.hook.base.MethodProxy; import com.lody.virtual.client.hook.utils.MethodParameterUtils; +import com.lody.virtual.helper.utils.VLog; import java.io.File; import java.lang.reflect.Method; +import java.util.UUID; + +import mirror.android.os.UserHandle; +import mirror.android.os.storage.StorageVolume; /** * @author Lody @@ -14,8 +22,12 @@ class MethodProxies { + + // StorageManager.getVolumeList() static class GetVolumeList extends MethodProxy { + static final String TAG = "GetVolumeList"; + @Override public String getMethodName() { return "getVolumeList"; @@ -23,6 +35,7 @@ public String getMethodName() { @Override public boolean beforeCall(Object who, Method method, Object... args) { + Log.d(TAG, "before call who:" + who + ", method:" + method.getName()); if (args == null || args.length == 0) { return super.beforeCall(who, method, args); } @@ -37,6 +50,56 @@ public boolean beforeCall(Object who, Method method, Object... args) { public Object afterCall(Object who, Method method, Object[] args, Object result) throws Throwable { return result; } + + @Override + public Object call(Object who, Method method, Object... args) throws Throwable { + Object result; + + // After 13, getVolumeList throw Neither user 10467 nor current process has android.permission.INTERACT_ACROSS_USERS. + // hook return manual StorageVolume array. + if (Build.VERSION.SDK_INT >= 33) { + final String id = "stub_primary"; + final File path = new File("/storage/emulated/0"); //System.getenv("EXTERNAL_STORAGE")); //Environment.getLegacyExternalStorageDirectory(); + final String description = VirtualCore.get().getContext().getString(android.R.string.unknownName); + final boolean primary = true; + final boolean primaryPhysical = true; + final boolean removable = primaryPhysical; + final boolean emulated = !primaryPhysical; + final boolean externallyManaged = false; + final boolean allowMassStorage = false; + final long maxFileSize = 0L; + int userId = (int) args[0]; + final android.os.UserHandle owner = UserHandle.ctor.newInstance(userId); + final String fsUuid = null; + final UUID uuid = null; + final String state = Environment.MEDIA_MOUNTED; + VLog.d(TAG, "id:" + id + ", path:" + path + ", desc:" + description + "primary:" + primary + ", userId:" + userId ); + +// StorageVolume constructor +// public StorageVolume(String id, File path, File internalPath, String description, +// boolean primary, boolean removable, boolean emulated, boolean externallyManaged, +// boolean allowMassStorage, long maxFileSize, UserHandle owner, UUID uuid, String fsUuid, +// String state) + android.os.storage.StorageVolume[] storageVolumes = { + StorageVolume.ctor.newInstance( + id, + path, + path, + description, + primary, + removable, + emulated, + externallyManaged, + allowMassStorage, maxFileSize, owner, + uuid /*uuid */, id, + state)}; + result = storageVolumes; + } else { + result = super.call(who, method, args); + } + + return result; + } } static class Mkdirs extends MethodProxy { diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MountServiceStub.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MountServiceStub.java index 3c4518e1a..486cea72c 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MountServiceStub.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/mount/MountServiceStub.java @@ -20,6 +20,13 @@ public MountServiceStub() { super(getInterfaceMethod(), "mount"); } + @Override + protected void onBindMethods() { + super.onBindMethods(); + + addMethodProxy(new MethodProxies.GetVolumeList()); + } + private static RefStaticMethod getInterfaceMethod() { if (BuildCompat.isOreo()) { return IStorageManager.Stub.asInterface; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/MethodProxies.java b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/MethodProxies.java index 93863747f..6375597a0 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/MethodProxies.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/client/hook/proxies/pm/MethodProxies.java @@ -30,6 +30,7 @@ import com.lody.virtual.helper.collection.ArraySet; import com.lody.virtual.helper.compat.ParceledListSliceCompat; import com.lody.virtual.helper.utils.ArrayUtils; +import com.lody.virtual.helper.utils.DataUtil; import com.lody.virtual.helper.utils.EncodeUtils; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.server.IPackageInstaller; @@ -158,7 +159,8 @@ public String getMethodName() { @Override public Object call(Object who, Method method, Object... args) throws Throwable { ComponentName componentName = (ComponentName) args[0]; - int flags = (int) args[1]; + // android 13, the type is long + int flags = DataUtil.safeToInt(args[1]); int userId = VUserHandle.myUserId(); ServiceInfo info = VPackageManager.get().getServiceInfo(componentName, flags, userId); if (info != null) { @@ -223,7 +225,9 @@ public Object call(Object who, Method method, Object... args) throws Throwable { return method.invoke(who, args); } int userId = VUserHandle.myUserId(); - int flags = (int) args[1]; + + // android 13, the type is long + int flags = DataUtil.safeToInt(args[1]); ActivityInfo info = VPackageManager.get().getActivityInfo(componentName, flags, userId); if (info == null) { info = (ActivityInfo) method.invoke(who, args); @@ -418,7 +422,8 @@ public String getMethodName() { @Override public Object call(Object who, Method method, Object... args) throws Throwable { String name = (String) args[0]; - int flags = (int) args[1]; + // android 13, the type is long + int flags = DataUtil.safeToInt(args[1]); int userId = VUserHandle.myUserId(); ProviderInfo info = VPackageManager.get().resolveContentProvider(name, flags, userId); if (info == null) { @@ -444,8 +449,9 @@ public String getMethodName() { public Object call(Object who, Method method, Object... args) throws Throwable { boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method); int userId = VUserHandle.myUserId(); + // android 13, the type is long List appResult = VPackageManager.get().queryIntentServices((Intent) args[0], - (String) args[1], (Integer) args[2], userId); + (String) args[1], DataUtil.safeToInt(args[2]), userId); Object _hostResult = method.invoke(who, args); if (_hostResult != null) { List hostResult = slice ? ParceledListSlice.getList.call(_hostResult) @@ -528,7 +534,7 @@ public Object call(Object who, Method method, Object... args) throws Throwable { boolean slice = ParceledListSliceCompat.isReturnParceledListSlice(method); int userId = VUserHandle.myUserId(); List appResult = VPackageManager.get().queryIntentActivities((Intent) args[0], - (String) args[1], (Integer) args[2], userId); + (String) args[1], DataUtil.safeToInt(args[2]), userId); Object _hostResult = method.invoke(who, args); if (_hostResult != null) { List hostResult = slice ? ParceledListSlice.getList.call(_hostResult) @@ -602,7 +608,7 @@ public String getMethodName() { @Override public Object call(Object who, Method method, Object... args) throws Throwable { String name = (String) args[0]; - int flags = (int) args[1]; + int flags = DataUtil.safeToInt(args[1]); PermissionGroupInfo info = VPackageManager.get().getPermissionGroupInfo(name, flags); if (info != null) { return info; @@ -632,7 +638,7 @@ public boolean beforeCall(Object who, Method method, Object... args) { @Override public Object call(Object who, Method method, Object... args) throws Throwable { String pkg = (String) args[0]; - int flags = (int) args[1]; + int flags = DataUtil.safeToInt(args[1]); int userId = VUserHandle.myUserId(); PackageInfo packageInfo = VPackageManager.get().getPackageInfo(pkg, flags, userId); if (packageInfo != null) { @@ -790,7 +796,7 @@ public String getMethodName() { public Object call(Object who, Method method, Object... args) throws Throwable { String processName = (String) args[0]; int uid = (int) args[1]; - int flags = (int) args[2]; + int flags = DataUtil.safeToInt(args[2]); List infos = VPackageManager.get().queryContentProviders(processName, uid, flags); if (ParceledListSliceCompat.isReturnParceledListSlice(method)) { return ParceledListSliceCompat.create(infos); @@ -951,7 +957,7 @@ public String getMethodName() { public Object call(Object who, Method method, Object... args) throws Throwable { Intent intent = (Intent) args[0]; String resolvedType = (String) args[1]; - int flags = (int) args[2]; + int flags = DataUtil.safeToInt(args[2]); int userId = VUserHandle.myUserId(); ResolveInfo resolveInfo = VPackageManager.get().resolveIntent(intent, resolvedType, flags, userId); if (resolveInfo == null) { @@ -1005,7 +1011,7 @@ public String getMethodName() { @Override public Object call(Object who, Method method, Object... args) throws Throwable { ComponentName componentName = (ComponentName) args[0]; - int flags = (int) args[1]; + int flags = DataUtil.safeToInt(args[1]); if (getHostPkg().equals(componentName.getPackageName())) { return method.invoke(who, args); } @@ -1137,7 +1143,7 @@ public Object call(Object who, Method method, Object... args) throws Throwable { if (getHostPkg().equals(componentName.getPackageName())) { return method.invoke(who, args); } - int flags = (int) args[1]; + int flags = DataUtil.safeToInt(args[1]); ActivityInfo info = VPackageManager.get().getReceiverInfo(componentName, flags, 0); if (info == null) { info = (ActivityInfo) method.invoke(who, args); diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/PackageParserCompat.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/PackageParserCompat.java index 3ed9127c6..2a64e11cc 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/PackageParserCompat.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/compat/PackageParserCompat.java @@ -10,6 +10,7 @@ import android.content.pm.PackageParser.Service; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; +import android.content.pm.SigningInfo; import android.os.Build; import android.os.Process; import android.util.DisplayMetrics; @@ -19,6 +20,7 @@ import java.io.File; +import mirror.android.content.pm.PackageParser33; import mirror.android.content.pm.PackageParserJellyBean; import mirror.android.content.pm.PackageParserJellyBean17; import mirror.android.content.pm.PackageParserLollipop; @@ -44,11 +46,13 @@ public class PackageParserCompat { public static final int[] GIDS = VirtualCore.get().getGids(); private static final int API_LEVEL = Build.VERSION.SDK_INT; private static final int myUserId = VUserHandle.getUserId(Process.myUid()); - private static final Object sUserState = API_LEVEL >= JELLY_BEAN_MR1 ? PackageUserState.ctor.newInstance() : null; + private static final Object sUserState = (API_LEVEL >= JELLY_BEAN_MR1 && API_LEVEL <= 32 /*Android 12L*/) ? PackageUserState.ctor.newInstance() : null; public static PackageParser createParser(File packageFile) { - if (API_LEVEL >= M) { + if (API_LEVEL >= 33) { + return PackageParser33.ctor.newInstance(); + } else if (API_LEVEL >= M) { return PackageParserMarshmallow.ctor.newInstance(); } else if (API_LEVEL >= LOLLIPOP_MR1) { return PackageParserLollipop22.ctor.newInstance(); @@ -67,7 +71,9 @@ public static Package parsePackage(PackageParser parser, File packageFile, int f if (BuildCompat.isQ()) { PackageParserP28.setCallback.call(parser, PackageParserP28.CallbackImpl.ctor.newInstance(VirtualCore.getPM())); } - + if (API_LEVEL >= 33) { + return PackageParser33.parsePackage.callWithException(parser, packageFile, flags); + } if (API_LEVEL >= M) { return PackageParserMarshmallow.parsePackage.callWithException(parser, packageFile, flags); } else if (API_LEVEL >= LOLLIPOP_MR1) { @@ -193,4 +199,16 @@ public static void collectCertificates(PackageParser parser, Package p, int flag mirror.android.content.pm.PackageParser.collectCertificates.call(parser, p, flags); } } + + public static SigningInfo createSigningInfo(Object signingDetails) { + if (API_LEVEL >= 33) { + // 33之后 + Object signatures = mirror.android.content.pm.PackageParser.SigningDetails.signatures.get(signingDetails); + Object pastSigningCertificates = mirror.android.content.pm.PackageParser.SigningDetails.pastSigningCertificates.get(signingDetails); + int signatureSchemeVersion = mirror.android.content.pm.PackageParser.SigningDetails.signatureSchemeVersion.get(signingDetails); + Object newDetail = mirror.android.content.pm.PackageParser.SigningDetailsUp33.ctor.newInstance(signatures, signatureSchemeVersion, pastSigningCertificates); + return mirror.android.content.pm.PackageParser.SigningInfoUp33.ctor.newInstance(newDetail); + } + return mirror.android.content.pm.PackageParser.SigningInfo.ctor.newInstance(signingDetails); + } } diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/DataUtil.java b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/DataUtil.java new file mode 100644 index 000000000..f81a47547 --- /dev/null +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/DataUtil.java @@ -0,0 +1,18 @@ +package com.lody.virtual.helper.utils; + +public class DataUtil { + + /** + * Since android 13(33), many types have changed to Long, and this function is suitable for this scenario + * @param data + * @return + */ + public static int safeToInt(Object data) { + if (data instanceof Long) { + return ((Long) data).intValue(); + } else if (data instanceof Integer) { + return (int) data; + } + return (int) data; + } +} diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java index 819b85115..659884876 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/os/VEnvironment.java @@ -159,11 +159,21 @@ public static File getUserSystemDirectory(int userId) { return new File(USER_DIRECTORY, String.valueOf(userId)); } + public static File getExternalStorageDirectory() { + try { + return Environment.getExternalStorageDirectory(); + } catch (Exception e) { // android 13 no permission will throw exception + return null; + } + } + public static File getVirtualStorageBaseDir() { - File externalFilesRoot = Environment.getExternalStorageDirectory(); + File externalFilesRoot = getExternalStorageDirectory(); + VLog.d(TAG, "getVirtualStorageBaseDir externalFilesRoot:" + externalFilesRoot); if (externalFilesRoot != null) { File vBaseDir = new File(externalFilesRoot, "VirtualXposed"); File vSdcard = new File(vBaseDir, "vsdcard"); + VLog.d(TAG, "getVirtualStorageBaseDir vBaseDir:" + vBaseDir + ", vSdcard:" + vSdcard); return ensureCreated(vSdcard); } return null; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstalledAppInfo.java b/VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstalledAppInfo.java index 675de4521..4c21fba5f 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstalledAppInfo.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/remote/InstalledAppInfo.java @@ -10,6 +10,7 @@ import com.lody.virtual.os.VEnvironment; import java.io.File; +import java.util.Arrays; /** * @author Lody @@ -23,6 +24,19 @@ public final class InstalledAppInfo implements Parcelable { public int appId; public String[] splitCodePaths; + + @Override + public String toString() { + return "InstalledAppInfo{" + + "packageName='" + packageName + '\'' + + ", apkPath='" + apkPath + '\'' + + ", libPath='" + libPath + '\'' + + ", dependSystem=" + dependSystem + + ", appId=" + appId + + ", splitCodePaths=" + Arrays.toString(splitCodePaths) + + '}'; + } + public InstalledAppInfo(String packageName, String apkPath, String libPath, boolean dependSystem, boolean skipDexOpt, int appId, String[] splitCodePaths) { this.packageName = packageName; this.apkPath = apkPath; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java index a7fa9f849..3eb168e46 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java @@ -262,6 +262,9 @@ private PackageInfo generatePackageInfo(VPackage p, PackageSetting ps, int flags if (packageInfo != null) { Parcel parcel = Parcel.obtain(); packageInfo.writeToParcel(parcel, 0); + + // Fixed packageInfo. After serialization and deserialization, the data is gone + parcel.setDataPosition(0); PackageInfo info = PackageInfo.CREATOR.createFromParcel(parcel); parcel.recycle(); return info; diff --git a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/PackageParserEx.java b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/PackageParserEx.java index e1d69702c..6c178dea0 100644 --- a/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/PackageParserEx.java +++ b/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/parser/PackageParserEx.java @@ -220,7 +220,8 @@ private static VPackage buildPackageCache(PackageParser.Package p) { System.arraycopy(signatures, 0, cache.mSignatures, 0, numberOfSigs); } } - cache.signingInfo = mirror.android.content.pm.PackageParser.SigningInfo.ctor.newInstance(signingDetails); + + cache.signingInfo = PackageParserCompat.createSigningInfo(signingDetails); // mirror.android.content.pm.PackageParser.SigningInfo.ctor.newInstance(signingDetails); } cache.mAppMetaData = p.mAppMetaData; cache.packageName = p.packageName; diff --git a/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser.java b/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser.java index de8086cae..dd6a3292d 100644 --- a/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser.java +++ b/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser.java @@ -20,9 +20,11 @@ import mirror.MethodReflectParams; import mirror.RefClass; import mirror.RefConstructor; +import mirror.RefInt; import mirror.RefMethod; import mirror.RefObject; import mirror.RefStaticMethod; +import mirror.android.util.Singleton; /** * @author Lody @@ -101,6 +103,8 @@ public static class Component { public static RefObject> intents; } + + public static class SigningInfo { public static Class TYPE = RefClass.load(SigningInfo.class, "android.content.pm.SigningInfo"); @@ -108,11 +112,38 @@ public static class SigningInfo { public static RefConstructor ctor; } + public static class SigningInfoUp33 { + public static Class TYPE = RefClass.load(SigningInfoUp33.class, "android.content.pm.SigningInfo"); + + @MethodReflectParams("android.content.pm.SigningDetails") + public static RefConstructor ctor; + } + + public static class SigningDetails { public static Class TYPE = RefClass.load(SigningDetails.class, "android.content.pm.PackageParser$SigningDetails"); public static RefObject signatures; public static RefObject pastSigningCertificates; + public static RefInt signatureSchemeVersion; + + public static RefMethod hasPastSigningCertificates; + public static RefMethod hasSignatures; + } + + public static class SigningDetailsUp33 { + public static Class TYPE = RefClass.load(SigningDetailsUp33.class, "android.content.pm.SigningDetails"); + +// Signature[] signatures, +// @SignatureSchemeVersion int signatureSchemeVersion, +// @Nullable Signature[] pastSigningCertificates + @MethodParams({Signature[].class, int.class, Signature[].class}) + public static RefConstructor ctor; + + + public static RefObject mSignatures; + public static RefObject mPastSigningCertificates; + public static RefMethod hasPastSigningCertificates; public static RefMethod hasSignatures; } diff --git a/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser33.java b/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser33.java new file mode 100644 index 000000000..ce7bef349 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/content/pm/PackageParser33.java @@ -0,0 +1,42 @@ +package mirror.android.content.pm; + +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageParser; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; + +import java.io.File; + +import mirror.MethodParams; +import mirror.MethodReflectParams; +import mirror.RefClass; +import mirror.RefConstructor; +import mirror.RefMethod; +import mirror.RefStaticMethod; + +/** + * @author Lody + */ + +public class PackageParser33 { + + + public static Class TYPE = RefClass.load(PackageParser33.class, "android.content.pm.PackageParser"); + @MethodReflectParams({"android.content.pm.PackageParser$Package", "int"}) + public static RefMethod collectCertificates; + public static RefConstructor ctor; + @MethodReflectParams({"android.content.pm.PackageParser$Activity", "int", "android.content.pm.pkg.FrameworkPackageUserState", "int"}) + public static RefStaticMethod generateActivityInfo; + @MethodReflectParams({"android.content.pm.PackageParser$Package", "int", "android.content.pm.pkg.FrameworkPackageUserState"}) + public static RefStaticMethod generateApplicationInfo; + @MethodReflectParams({"android.content.pm.PackageParser$Package", "[I", "int", "long", "long", "java.util.Set", "android.content.pm.pkg.FrameworkPackageUserState"}) + public static RefStaticMethod generatePackageInfo; + @MethodReflectParams({"android.content.pm.PackageParser$Provider", "int", "android.content.pm.pkg.FrameworkPackageUserState", "int"}) + public static RefStaticMethod generateProviderInfo; + @MethodReflectParams({"android.content.pm.PackageParser$Service", "int", "android.content.pm.pkg.FrameworkPackageUserState", "int"}) + public static RefStaticMethod generateServiceInfo; + @MethodParams({File.class, int.class}) + public static RefMethod parsePackage; +} diff --git a/VirtualApp/lib/src/main/java/mirror/android/os/storage/StorageVolume.java b/VirtualApp/lib/src/main/java/mirror/android/os/storage/StorageVolume.java new file mode 100644 index 000000000..657474ee9 --- /dev/null +++ b/VirtualApp/lib/src/main/java/mirror/android/os/storage/StorageVolume.java @@ -0,0 +1,35 @@ +package mirror.android.os.storage; + +import java.io.File; +import java.util.UUID; + +import mirror.MethodParams; +import mirror.RefClass; +import mirror.RefConstructor; +import mirror.RefMethod; +import mirror.RefObject; +import android.os.UserHandle; + +public class StorageVolume { + + public static Class Class = RefClass.load(StorageVolume.class, "android.os.storage.StorageVolume"); + + + + // StorageVolume(String id, File path, File internalPath, String description, + // boolean primary, boolean removable, boolean emulated, boolean externallyManaged, + // boolean allowMassStorage, long maxFileSize, UserHandle owner, UUID uuid, String fsUuid, + // String state) + // upper android 13 (33) + @MethodParams({String.class, File.class, File.class, String.class, + boolean.class, boolean.class, boolean.class, boolean.class, + boolean.class, long.class, UserHandle.class, UUID.class, String.class, + String.class + }) + public static RefConstructor ctor; + + + public static RefObject mPath; + + public static RefMethod getPath; +}