diff --git a/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java b/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java index 57f3c607..ca631b9e 100644 --- a/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java +++ b/core/src/main/java/org/lsposed/lspd/core/ApplicationServiceClient.java @@ -57,15 +57,6 @@ public class ApplicationServiceClient implements ILSPApplicationService, IBinder } } - @Override - public IBinder requestModuleBinder(String name) { - try { - return service.requestModuleBinder(name); - } catch (RemoteException | NullPointerException ignored) { - } - return null; - } - @Override public List getLegacyModulesList() { try { diff --git a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java index 1b8a7a11..90fc2493 100644 --- a/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java +++ b/core/src/main/java/org/lsposed/lspd/hooker/LoadedApkGetCLHooker.java @@ -25,7 +25,6 @@ import static org.lsposed.lspd.core.ApplicationServiceClient.serviceClient; import android.app.ActivityThread; import android.app.AndroidAppHelper; import android.app.LoadedApk; -import android.os.IBinder; import org.lsposed.lspd.impl.LSPosedContext; import org.lsposed.lspd.util.Hookers; @@ -89,10 +88,7 @@ public class LoadedApkGetCLHooker extends XC_MethodHook { lpparam.appInfo = loadedApk.getApplicationInfo(); lpparam.isFirstApplication = isFirstApplication; - IBinder moduleBinder = serviceClient.requestModuleBinder(lpparam.packageName); - if (moduleBinder != null) { - hookNewXSP(lpparam); - } + hookNewXSP(lpparam); Hookers.logD("Call handleLoadedPackage: packageName=" + lpparam.packageName + " processName=" + lpparam.processName + " isFirstApplication=" + isFirstApplication + " classLoader=" + lpparam.classLoader + " appInfo=" + lpparam.appInfo); XC_LoadPackage.callAll(lpparam); diff --git a/daemon/src/main/java/io/github/libxposed/service/XposedService.java b/daemon/src/main/java/io/github/libxposed/service/XposedService.java new file mode 100644 index 00000000..3bba97a6 --- /dev/null +++ b/daemon/src/main/java/io/github/libxposed/service/XposedService.java @@ -0,0 +1,15 @@ +package io.github.libxposed.service; + +import io.github.xposed.xposedservice.IXposedService; + +public abstract class XposedService extends IXposedService.Stub { + + public static final int API = 100; + public static final String AUTHORITY_SUFFIX = ".XposedService"; + public static final String SEND_BINDER = "SendBinder"; + + @Override + public final int getVersion() { + return API; + } +} diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java b/daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java index d3840877..24057ca2 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java @@ -25,6 +25,7 @@ import android.annotation.SuppressLint; import android.app.IActivityManager; import android.app.IApplicationThread; import android.app.IServiceConnection; +import android.app.IUidObserver; import android.app.ProfilerInfo; import android.content.Context; import android.content.IContentProvider; @@ -194,4 +195,9 @@ public class ActivityManagerService { } } + public static void registerUidObserver(IUidObserver observer, int which, int cutpoint, String callingPackage) throws RemoteException { + IActivityManager am = getActivityManager(); + if (am == null) return; + am.registerUidObserver(observer, which, cutpoint, callingPackage); + } } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java index 8c452969..c2b70316 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -151,15 +151,6 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { return bundle; } - @Override - public IBinder requestModuleBinder(String name) throws RemoteException { - var processInfo = ensureRegistered(); - if (ConfigManager.getInstance().isModule(processInfo.uid, name)) { - ConfigManager.getInstance().ensureModulePrefsPermission(processInfo.uid, name); - return ServiceManager.getModuleService(name); - } else return null; - } - @Override public ParcelFileDescriptor requestInjectedManagerBinder(List binder) throws RemoteException { var processInfo = ensureRegistered(); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java index 1afe5f53..195c75a0 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPModuleService.java @@ -19,27 +19,95 @@ package org.lsposed.lspd.service; -import android.os.IBinder; +import android.app.IUidObserver; +import android.content.AttributionSource; +import android.os.Build; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; -import org.lsposed.daemon.BuildConfig; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; -import io.github.xposed.xposedservice.IXposedService; +import hidden.HiddenApiBridge; +import io.github.libxposed.service.XposedService; -public class LSPModuleService extends IXposedService.Stub { +public class LSPModuleService extends XposedService { - final private String name; + private static final String TAG = "LSPosedModuleService"; - public LSPModuleService(String name) { - this.name = name; + private final Set uidSet = ConcurrentHashMap.newKeySet(); + private final IUidObserver uidObserver = new IUidObserver.Stub() { + @Override + public void onUidActive(int uid) { + uidStarts(uid); + } + + @Override + public void onUidCachedChanged(int uid, boolean cached) { + if (!cached) uidStarts(uid); + } + + @Override + public void onUidIdle(int uid, boolean disabled) { + uidStarts(uid); + } + + @Override + public void onUidGone(int uid, boolean disabled) { + uidSet.remove(uid); + } + }; + + void registerObserver() { + uidSet.clear(); + int flags = HiddenApiBridge.ActivityManager_UID_OBSERVER_ACTIVE() + | HiddenApiBridge.ActivityManager_UID_OBSERVER_GONE() + | HiddenApiBridge.ActivityManager_UID_OBSERVER_IDLE() + | HiddenApiBridge.ActivityManager_UID_OBSERVER_CACHED(); + try { + ActivityManagerService.registerUidObserver(uidObserver, flags, HiddenApiBridge.ActivityManager_PROCESS_STATE_UNKNOWN(), null); + Log.i(TAG, "registered uid observer"); + } catch (RemoteException e) { + Log.e(TAG, "failed to register uid observer", e); + } } - @Override - public IBinder asBinder() { - return this; + private void uidStarts(int uid) { + if (!uidSet.contains(uid)) { + uidSet.add(uid); + var module = ConfigManager.getInstance().getModule(uid); + if (module != null) sendBinder(uid, module); + } } - @Override - public int getVersion() { - return BuildConfig.API_CODE; + private void sendBinder(int uid, String name) { + try { + int userId = uid / PackageService.PER_USER_RANGE; + var authority = name + AUTHORITY_SUFFIX; + var provider = ActivityManagerService.getContentProvider(authority, userId); + if (provider == null) { + Log.d(TAG, "no service provider for " + name); + return; + } + var extra = new Bundle(); + extra.putBinder("binder", asBinder()); + Bundle reply = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + reply = provider.call(new AttributionSource.Builder(1000).setPackageName("android").build(), + authority, SEND_BINDER, null, extra); + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + reply = provider.call("android", null, authority, SEND_BINDER, null, extra); + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { + reply = provider.call("android", authority, SEND_BINDER, null, extra); + } + if (reply != null) { + Log.d(TAG, "sent module binder to " + name); + } else { + Log.w(TAG, "failed to send module binder to " + name); + } + } catch (RemoteException | NoSuchMethodError e) { + Log.w(TAG, "failed to send module binder for uid " + uid, e); + } } } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java index 580be54b..b7d32f75 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -36,7 +36,6 @@ import com.android.internal.os.BinderInternal; import org.lsposed.daemon.BuildConfig; import java.io.File; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -44,12 +43,12 @@ import hidden.HiddenApiBridge; public class ServiceManager { public static final String TAG = "LSPosedService"; - private static final ConcurrentHashMap moduleServices = new ConcurrentHashMap<>(); private static final File globalNamespace = new File("/proc/1/root"); @SuppressWarnings("FieldCanBeLocal") private static LSPosedService mainService = null; private static LSPApplicationService applicationService = null; private static LSPManagerService managerService = null; + private static LSPModuleService moduleService = null; private static LSPSystemServerService systemServerService = null; private static LogcatService logcatService = null; private static Dex2OatService dex2OatService = null; @@ -114,6 +113,7 @@ public class ServiceManager { mainService = new LSPosedService(); applicationService = new LSPApplicationService(); managerService = new LSPManagerService(); + moduleService = new LSPModuleService(); systemServerService = new LSPSystemServerService(systemServerMaxRetry); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { dex2OatService = new Dex2OatService(); @@ -142,6 +142,7 @@ public class ServiceManager { @Override public void onSystemServerRestarted() { Log.w(TAG, "system restarted..."); + moduleService.registerObserver(); } @Override @@ -152,6 +153,7 @@ public class ServiceManager { Log.w(TAG, "no response from bridge"); } systemServerService.maybeRetryInject(); + moduleService.registerObserver(); } @Override @@ -171,10 +173,6 @@ public class ServiceManager { throw new RuntimeException("Main thread loop unexpectedly exited"); } - public static LSPModuleService getModuleService(String module) { - return moduleServices.computeIfAbsent(module, LSPModuleService::new); - } - public static LSPApplicationService getApplicationService() { return applicationService; } diff --git a/hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java b/hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java index 1ca10128..8055bf37 100644 --- a/hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java +++ b/hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java @@ -19,6 +19,7 @@ package hidden; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -127,4 +128,24 @@ public class HiddenApiBridge { return Os.ioctlInt(fd, cmd); } } + + public static int ActivityManager_UID_OBSERVER_GONE() { + return ActivityManager.UID_OBSERVER_GONE; + } + + public static int ActivityManager_UID_OBSERVER_ACTIVE() { + return ActivityManager.UID_OBSERVER_ACTIVE; + } + + public static int ActivityManager_UID_OBSERVER_IDLE() { + return ActivityManager.UID_OBSERVER_IDLE; + } + + public static int ActivityManager_UID_OBSERVER_CACHED() { + return ActivityManager.UID_OBSERVER_CACHED; + } + + public static int ActivityManager_PROCESS_STATE_UNKNOWN() { + return ActivityManager.PROCESS_STATE_UNKNOWN; + } } diff --git a/hiddenapi/stubs/src/main/java/android/app/ActivityManager.java b/hiddenapi/stubs/src/main/java/android/app/ActivityManager.java new file mode 100644 index 00000000..b38f5714 --- /dev/null +++ b/hiddenapi/stubs/src/main/java/android/app/ActivityManager.java @@ -0,0 +1,9 @@ +package android.app; + +public class ActivityManager { + public static int UID_OBSERVER_GONE; + public static int UID_OBSERVER_ACTIVE; + public static int UID_OBSERVER_IDLE; + public static int UID_OBSERVER_CACHED; + public static int PROCESS_STATE_UNKNOWN; +} diff --git a/hiddenapi/stubs/src/main/java/android/app/IActivityManager.java b/hiddenapi/stubs/src/main/java/android/app/IActivityManager.java index f2bc2bfd..60ce62f2 100644 --- a/hiddenapi/stubs/src/main/java/android/app/IActivityManager.java +++ b/hiddenapi/stubs/src/main/java/android/app/IActivityManager.java @@ -40,6 +40,7 @@ public interface IActivityManager extends IInterface { String[] requiredPermissions, String[] excludedPermissions, String[] excludePackages, int appOp, Bundle bOptions, boolean serialized, boolean sticky, int userId) throws RemoteException; + @RequiresApi(31) int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId, Intent intent, String resolvedType, IIntentReceiver resultTo, @@ -122,6 +123,8 @@ public interface IActivityManager extends IInterface { Configuration getConfiguration() throws RemoteException; + void registerUidObserver(IUidObserver observer, int which, int cutpoint, String callingPackage) throws RemoteException; + abstract class Stub extends Binder implements IActivityManager { public static int TRANSACTION_setActivityController; diff --git a/hiddenapi/stubs/src/main/java/android/app/IUidObserver.java b/hiddenapi/stubs/src/main/java/android/app/IUidObserver.java new file mode 100644 index 00000000..676e509a --- /dev/null +++ b/hiddenapi/stubs/src/main/java/android/app/IUidObserver.java @@ -0,0 +1,17 @@ +package android.app; + +import android.os.Binder; + +public interface IUidObserver { + + void onUidGone(int uid, boolean disabled); + + void onUidActive(int uid); + + void onUidIdle(int uid, boolean disabled); + + void onUidCachedChanged(int uid, boolean cached); + + abstract class Stub extends Binder implements IUidObserver { + } +} diff --git a/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl b/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl index 9ee7943d..9c656e72 100644 --- a/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl +++ b/services/daemon-service/src/main/aidl/org/lsposed/lspd/service/ILSPApplicationService.aidl @@ -3,8 +3,6 @@ package org.lsposed.lspd.service; import org.lsposed.lspd.models.Module; interface ILSPApplicationService { - IBinder requestModuleBinder(String name); - List getLegacyModulesList(); List getModulesList();