From 0df0a14808a5b56ef91d6655bc5b7c118e205263 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 15 May 2021 03:05:04 +0800 Subject: [PATCH] [core] Workaround for service manager overwritten on Android R (#581) --- .../lspd/service/ILSPSystemServerService.aidl | 7 ++ .../config/LSPApplicationServiceClient.java | 18 ++-- .../lspd/service/ActivityManagerService.java | 21 +++-- .../lsposed/lspd/service/BridgeService.java | 38 ++++----- .../lspd/service/LSPApplicationService.java | 8 +- .../lspd/service/LSPSystemServerService.java | 82 +++++++++++++++++++ .../lsposed/lspd/service/LSPosedService.java | 7 -- .../lsposed/lspd/service/PackageService.java | 19 +++-- .../lsposed/lspd/service/PowerService.java | 19 +++-- .../lsposed/lspd/service/ServiceManager.java | 16 ++-- .../org/lsposed/lspd/service/UserService.java | 19 +++-- .../java/android/os/IServiceCallback.java | 13 +++ .../main/java/android/os/IServiceManager.java | 14 +++- .../android/internal/os/BinderInternal.java | 7 ++ 14 files changed, 209 insertions(+), 79 deletions(-) create mode 100644 core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl create mode 100644 core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java create mode 100644 hiddenapi-stubs/src/main/java/android/os/IServiceCallback.java create mode 100644 hiddenapi-stubs/src/main/java/com/android/internal/os/BinderInternal.java diff --git a/core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl b/core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl new file mode 100644 index 00000000..25d6a72f --- /dev/null +++ b/core/src/main/aidl/org/lsposed/lspd/service/ILSPSystemServerService.aidl @@ -0,0 +1,7 @@ +package org.lsposed.lspd.service; + +import org.lsposed.lspd.service.ILSPApplicationService; + +interface ILSPSystemServerService { + ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) = 1; +} diff --git a/core/src/main/java/org/lsposed/lspd/config/LSPApplicationServiceClient.java b/core/src/main/java/org/lsposed/lspd/config/LSPApplicationServiceClient.java index 8336e783..56b1a3af 100644 --- a/core/src/main/java/org/lsposed/lspd/config/LSPApplicationServiceClient.java +++ b/core/src/main/java/org/lsposed/lspd/config/LSPApplicationServiceClient.java @@ -36,21 +36,21 @@ public class LSPApplicationServiceClient implements ILSPApplicationService { static String processName = null; public static LSPApplicationServiceClient serviceClient = null; + private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + serviceBinder.unlinkToDeath(this, 0); + serviceBinder = null; + service = null; + } + }; public static void Init(IBinder binder, String niceName) { if (serviceClient == null && binder != null && serviceBinder == null && service == null) { serviceBinder = binder; processName = niceName; try { - serviceBinder.linkToDeath( - new IBinder.DeathRecipient() { - @Override - public void binderDied() { - serviceBinder.unlinkToDeath(this, 0); - serviceBinder = null; - service = null; - } - }, 0); + serviceBinder.linkToDeath(recipient, 0); } catch (RemoteException e) { Utils.logE("link to death error: ", e); } diff --git a/core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java b/core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java index 79dc1df9..091370d4 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java +++ b/core/src/main/java/org/lsposed/lspd/service/ActivityManagerService.java @@ -34,22 +34,25 @@ import static org.lsposed.lspd.service.ServiceManager.TAG; public class ActivityManagerService { private static IActivityManager am = null; + private static IBinder binder = null; + private static final IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w(TAG, "am is dead"); + binder.unlinkToDeath(this, 0); + binder = null; + am = null; + } + }; + public static IActivityManager getActivityManager() { if (binder == null && am == null) { binder = ServiceManager.getService("activity"); if (binder == null) return null; try { - binder.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - Log.w(TAG, "am is dead"); - binder.unlinkToDeath(this, 0); - binder = null; - am = null; - } - }, 0); + binder.linkToDeath(deathRecipient, 0); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(e)); } diff --git a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java index 84a73ed4..1e2435a6 100644 --- a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -64,13 +64,8 @@ public class BridgeService { private static ILSPosedService service = null; // for service - static class BridgeServiceDeathRecipient implements IBinder.DeathRecipient { - private final IBinder bridgeService; - - BridgeServiceDeathRecipient(IBinder bridgeService) throws RemoteException { - this.bridgeService = bridgeService; - bridgeService.linkToDeath(this, 0); - } + private static IBinder bridgeService; + private static final IBinder.DeathRecipient bridgeRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { @@ -96,16 +91,21 @@ public class BridgeService { } bridgeService.unlinkToDeath(this, 0); + bridgeService = null; listener.onSystemServerDied(); sendToBridge(serviceBinder, true); } - } + }; // for client - private static final IBinder.DeathRecipient LSPSERVICE_DEATH_RECIPIENT = () -> { - serviceBinder = null; - service = null; - Log.e(TAG, "service is dead"); + private static final IBinder.DeathRecipient serviceRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + serviceBinder.unlinkToDeath(this, 0); + serviceBinder = null; + service = null; + Log.e(TAG, "service is dead"); + } }; public interface Listener { @@ -121,7 +121,6 @@ public class BridgeService { // For service private static void sendToBridge(IBinder binder, boolean isRestart) { - IBinder bridgeService; do { bridgeService = ServiceManager.getService(SERVICE_NAME); if (bridgeService != null && bridgeService.pingBinder()) { @@ -143,7 +142,7 @@ public class BridgeService { } try { - new BridgeServiceDeathRecipient(bridgeService); + bridgeService.linkToDeath(bridgeRecipient, 0); } catch (Throwable e) { Log.w(TAG, "linkToDeath " + Log.getStackTraceString(e)); sendToBridge(binder, false); @@ -218,15 +217,16 @@ public class BridgeService { } }); } else { - serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0); + serviceBinder.unlinkToDeath(serviceRecipient, 0); } Binder.restoreCallingIdentity(token); serviceBinder = Binder_allowBlocking(binder); service = ILSPosedService.Stub.asInterface(serviceBinder); try { - serviceBinder.linkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0); - } catch (RemoteException ignored) { + serviceBinder.linkToDeath(serviceRecipient, 0); + } catch (Throwable e) { + Log.e(TAG, "service link to death: ", e); } Log.i(TAG, "binder received"); @@ -324,8 +324,8 @@ public class BridgeService { public static IBinder getApplicationServiceForSystemServer(IBinder binder, IBinder heartBeat) { if (binder == null || heartBeat == null) return null; try { - ILSPosedService service = ILSPosedService.Stub.asInterface(binder); - ILSPApplicationService applicationService = service.requestApplicationService(Process.myUid(), Process.myPid(), "android", heartBeat); + var service = ILSPSystemServerService.Stub.asInterface(binder); + var applicationService = service.requestApplicationService(Process.myUid(), Process.myPid(), "android", heartBeat); if (applicationService != null) return applicationService.asBinder(); } catch (Throwable e) { Log.e(TAG, Log.getStackTraceString(e)); diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java b/core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java index fa4b8cbe..ac5636db 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -35,18 +35,22 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { // private final static Set> cache = ConcurrentHashMap.newKeySet(); private final static Set handles = ConcurrentHashMap.newKeySet(); + private final static Set recipients = ConcurrentHashMap.newKeySet(); public boolean registerHeartBeat(int uid, int pid, IBinder handle) { try { - handle.linkToDeath(new DeathRecipient() { + var recipient = new DeathRecipient() { @Override public void binderDied() { Log.d(TAG, "pid=" + pid + " uid=" + uid + " is dead."); cache.remove(new Pair<>(uid, pid)); handles.remove(handle); handle.unlinkToDeath(this, 0); + recipients.remove(this); } - }, 0); + }; + recipients.add(recipient); + handle.linkToDeath(recipient, 0); handles.add(handle); cache.add(new Pair<>(uid, pid)); return true; diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java b/core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java new file mode 100644 index 00000000..482e4355 --- /dev/null +++ b/core/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java @@ -0,0 +1,82 @@ +package org.lsposed.lspd.service; + +import static org.lsposed.lspd.service.ServiceManager.TAG; +import static org.lsposed.lspd.service.ServiceManager.getSystemServiceManager; + +import android.os.Build; +import android.os.IBinder; +import android.os.IServiceCallback; +import android.os.Parcel; +import android.os.RemoteException; +import android.util.Log; + +public class LSPSystemServerService extends ILSPSystemServerService.Stub implements IBinder.DeathRecipient { + + public static final String PROXY_SERVICE_NAME = "serial"; + + private IBinder originService = null; + + public void putBinderForSystemServer() { + android.os.ServiceManager.addService(PROXY_SERVICE_NAME, this); + binderDied(); + } + + private final IServiceCallback serviceCallback = new IServiceCallback.Stub() { + @Override + public void onRegistration(String name, IBinder binder) { + if (name.equals(PROXY_SERVICE_NAME) && binder != null && binder != LSPSystemServerService.this) { + Log.d(TAG, "Register " + name + " " + binder); + originService = binder; + LSPSystemServerService.this.linkToDeath(); + } + } + + @Override + public IBinder asBinder() { + return this; + } + }; + + public LSPSystemServerService() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + try { + getSystemServiceManager().registerForNotifications(PROXY_SERVICE_NAME, serviceCallback); + } catch (Throwable e) { + Log.e(TAG, "unregister: ", e); + } + } + } + + @Override + public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) throws RemoteException { + if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName)) + return null; + else + return ServiceManager.requestApplicationService(uid, pid, heartBeat); + } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + if (originService != null) { + return originService.transact(code, data, reply, flags); + } + + return super.onTransact(code, data, reply, flags); + } + + public void linkToDeath() { + try { + originService.linkToDeath(this, 0); + } catch (Throwable e) { + Log.e(TAG, "system server service: link to death", e); + } + } + + @Override + public void binderDied() { + if (originService != null) { + originService.unlinkToDeath(this, 0); + originService = null; + } + } +} diff --git a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java b/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java index c6c79b8e..b7464a51 100644 --- a/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java +++ b/core/src/main/java/org/lsposed/lspd/service/LSPosedService.java @@ -42,12 +42,6 @@ public class LSPosedService extends ILSPosedService.Stub { Log.w(TAG, "Someone else got my binder!?"); return null; } - if (uid == 1000 && processName.equals("android")) { - if (ConfigManager.getInstance().shouldSkipSystemServer()) - return null; - else - return ServiceManager.requestApplicationService(uid, pid, heartBeat); - } if (ConfigManager.getInstance().shouldSkipProcess(new ConfigManager.ProcessScope(processName, uid))) { Log.d(TAG, "Skipped " + processName + "/" + uid); return null; @@ -60,7 +54,6 @@ public class LSPosedService extends ILSPosedService.Stub { return ServiceManager.requestApplicationService(uid, pid, heartBeat); } - @Override public void dispatchPackageChanged(Intent intent) throws RemoteException { if (Binder.getCallingUid() != 1000 || intent == null) return; diff --git a/core/src/main/java/org/lsposed/lspd/service/PackageService.java b/core/src/main/java/org/lsposed/lspd/service/PackageService.java index 4d1691af..cdb8aa6e 100644 --- a/core/src/main/java/org/lsposed/lspd/service/PackageService.java +++ b/core/src/main/java/org/lsposed/lspd/service/PackageService.java @@ -67,21 +67,22 @@ import hidden.HiddenApiBridge; public class PackageService { private static IPackageManager pm = null; private static IBinder binder = null; + private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w(TAG, "pm is dead"); + binder.unlinkToDeath(this, 0); + binder = null; + pm = null; + } + }; public static IPackageManager getPackageManager() { if (binder == null && pm == null) { binder = ServiceManager.getService("package"); if (binder == null) return null; try { - binder.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - Log.w(TAG, "pm is dead"); - binder.unlinkToDeath(this, 0); - binder = null; - pm = null; - } - }, 0); + binder.linkToDeath(recipient, 0); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(e)); } diff --git a/core/src/main/java/org/lsposed/lspd/service/PowerService.java b/core/src/main/java/org/lsposed/lspd/service/PowerService.java index f3f81b4a..a1862c5f 100644 --- a/core/src/main/java/org/lsposed/lspd/service/PowerService.java +++ b/core/src/main/java/org/lsposed/lspd/service/PowerService.java @@ -11,21 +11,22 @@ import static org.lsposed.lspd.service.ServiceManager.TAG; public class PowerService { private static IPowerManager pm = null; private static IBinder binder = null; + private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w(TAG, "pm is dead"); + binder.unlinkToDeath(this, 0); + binder = null; + pm = null; + } + }; public static IPowerManager getPowerManager() { if (binder == null && pm == null) { binder = ServiceManager.getService("power"); if (binder == null) return null; try { - binder.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - Log.w(TAG, "pm is dead"); - binder.unlinkToDeath(this, 0); - binder = null; - pm = null; - } - }, 0); + binder.linkToDeath(recipient, 0); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(e)); } diff --git a/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java b/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java index 9b35c9c9..f023904f 100644 --- a/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/core/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -20,18 +20,23 @@ package org.lsposed.lspd.service; import android.content.Context; -import android.os.Build; import android.os.IBinder; +import android.os.IServiceManager; import android.os.Looper; import android.util.Log; +import com.android.internal.os.BinderInternal; + import org.lsposed.lspd.BuildConfig; +import hidden.HiddenApiBridge; + public class ServiceManager { private static LSPosedService mainService = null; private static LSPModuleService moduleService = null; private static LSPApplicationService applicationService = null; private static LSPManagerService managerService = null; + private static LSPSystemServerService systemServerService = null; public static final String TAG = "LSPosedService"; private static void waitSystemService(String name) { @@ -45,8 +50,8 @@ public class ServiceManager { } } - private static void putBinderForSystemServer() { - android.os.ServiceManager.addService("serial", mainService); + public static IServiceManager getSystemServiceManager() { + return IServiceManager.Stub.asInterface(HiddenApiBridge.Binder_allowBlocking(BinderInternal.getContextObject())); } // call by ourselves @@ -63,8 +68,9 @@ public class ServiceManager { moduleService = new LSPModuleService(); applicationService = new LSPApplicationService(); managerService = new LSPManagerService(); + systemServerService = new LSPSystemServerService(); - putBinderForSystemServer(); + systemServerService.putBinderForSystemServer(); waitSystemService("package"); waitSystemService("activity"); @@ -89,7 +95,7 @@ public class ServiceManager { @Override public void onSystemServerDied() { Log.w(TAG, "system server died"); - putBinderForSystemServer(); + systemServerService.putBinderForSystemServer(); } }); diff --git a/core/src/main/java/org/lsposed/lspd/service/UserService.java b/core/src/main/java/org/lsposed/lspd/service/UserService.java index e5bf8d70..0ef46eed 100644 --- a/core/src/main/java/org/lsposed/lspd/service/UserService.java +++ b/core/src/main/java/org/lsposed/lspd/service/UserService.java @@ -34,21 +34,22 @@ import static org.lsposed.lspd.service.ServiceManager.TAG; public class UserService { private static IUserManager um = null; private static IBinder binder = null; + private static IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w(TAG, "um is dead"); + binder.unlinkToDeath(this, 0); + binder = null; + um = null; + } + }; public static IUserManager getUserManager() { if (binder == null && um == null) { binder = ServiceManager.getService("user"); if (binder == null) return null; try { - binder.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - Log.w(TAG, "um is dead"); - binder.unlinkToDeath(this, 0); - binder = null; - um = null; - } - }, 0); + binder.linkToDeath(recipient, 0); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(e)); } diff --git a/hiddenapi-stubs/src/main/java/android/os/IServiceCallback.java b/hiddenapi-stubs/src/main/java/android/os/IServiceCallback.java new file mode 100644 index 00000000..d3543024 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/os/IServiceCallback.java @@ -0,0 +1,13 @@ +package android.os; +public interface IServiceCallback extends IInterface +{ + public static abstract class Stub extends android.os.Binder implements android.os.IServiceCallback { + } + /** + * Called when a service is registered. + * + * @param name the service name that has been registered with + * @param binder the binder that is registered + */ + public void onRegistration(java.lang.String name, android.os.IBinder binder) throws android.os.RemoteException; +} diff --git a/hiddenapi-stubs/src/main/java/android/os/IServiceManager.java b/hiddenapi-stubs/src/main/java/android/os/IServiceManager.java index cfcfce01..7a1b1961 100644 --- a/hiddenapi-stubs/src/main/java/android/os/IServiceManager.java +++ b/hiddenapi-stubs/src/main/java/android/os/IServiceManager.java @@ -1,4 +1,16 @@ package android.os; -public interface IServiceManager { +public interface IServiceManager extends IInterface { + + void tryUnregisterService(java.lang.String name, android.os.IBinder service); + + IBinder getService(String name); + + public void registerForNotifications(String name, IServiceCallback cb); + + abstract class Stub extends Binder implements IServiceManager { + public static IServiceManager asInterface(IBinder obj) { + throw new UnsupportedOperationException(); + } + } } diff --git a/hiddenapi-stubs/src/main/java/com/android/internal/os/BinderInternal.java b/hiddenapi-stubs/src/main/java/com/android/internal/os/BinderInternal.java new file mode 100644 index 00000000..728c2ab5 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/com/android/internal/os/BinderInternal.java @@ -0,0 +1,7 @@ +package com.android.internal.os; + +import android.os.IBinder; + +public class BinderInternal { + public static final native IBinder getContextObject(); +}