From c770c41268ba3301a2cfe7e495a960ff5b83c94e Mon Sep 17 00:00:00 2001 From: Muntashir Al-Islam Date: Sun, 12 Nov 2023 11:23:28 +0600 Subject: [PATCH] [Refactor] Fix launching privileged service on OnePlus devices Thanks: John Wu Signed-off-by: Muntashir Al-Islam --- .../AppManager/ipc/RootService.java | 2 +- .../AppManager/ipc/RootServiceManager.java | 2 +- .../AppManager/ipc/RootServiceServer.java | 14 +++++++++----- .../AppManager/utils/ContextUtils.java | 19 ++++++++++++++----- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootService.java b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootService.java index 11d8c289362..3eb8c4e85fc 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootService.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootService.java @@ -256,7 +256,7 @@ public ComponentName getComponentName() { @SuppressLint("RestrictedApi") @Override public final Context getApplicationContext() { - return ContextUtils.getContext(); + return ContextUtils.rootContext; } /** diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceManager.java b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceManager.java index f3391153bcf..43ee4c7aed8 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceManager.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceManager.java @@ -110,7 +110,7 @@ static Intent getBroadcastIntent(IBinder binder, boolean isDaemon) { Bundle bundle = new Bundle(); bundle.putBinder(BUNDLE_BINDER_KEY, binder); return new Intent(RECEIVER_BROADCAST) - .setPackage(ContextUtils.context.getPackageName()) + .setPackage(ContextUtils.rootContext.getPackageName()) .addFlags(HiddenAPIs.FLAG_RECEIVER_FROM_SHELL) .putExtra(INTENT_DAEMON_KEY, isDaemon) .putExtra(INTENT_BUNDLE_KEY, bundle); diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceServer.java b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceServer.java index 2f3b23bb564..b5c171d458f 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceServer.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceServer.java @@ -53,6 +53,7 @@ public class RootServiceServer extends IRootServiceManager.Stub implements Runnable { public static final String TAG = RootServiceServer.class.getSimpleName(); + @SuppressLint("StaticFieldLeak") private static RootServiceServer sInstance; public static RootServiceServer getInstance(Context context) { @@ -67,11 +68,13 @@ public static RootServiceServer getInstance(Context context) { private final Map mServices = new ArrayMap<>(); private final SparseArray mClients = new SparseArray<>(); private final boolean mIsDaemon; + private final Context mContext; @SuppressWarnings("rawtypes") private RootServiceServer(Context context) { Shell.enableVerboseLogging = System.getenv(LOGGING_ENV) != null; - ContextUtils.context = Utils.getContextImpl(context); + mContext = context; + ContextUtils.rootContext = context; // Wait for debugger to attach if needed if (System.getenv(DEBUG_ENV) != null) { @@ -144,9 +147,9 @@ public void broadcast(int uid) { Intent intent = RootServiceManager.getBroadcastIntent(this, mIsDaemon); if (Build.VERSION.SDK_INT >= 24) { UserHandle h = UserHandle.getUserHandleForUid(uid); - ContextUtils.context.sendBroadcastAsUser(intent, h); + mContext.sendBroadcastAsUser(intent, h); } else { - ContextUtils.context.sendBroadcast(intent); + mContext.sendBroadcast(intent); } } @@ -197,6 +200,7 @@ public void register(RootService service) { mServices.put(service.getComponentName(), s); } + @Nullable private IBinder bindInternal(int uid, Intent intent) throws Exception { ClientProcess c = mClients.get(uid); if (c == null) @@ -206,10 +210,10 @@ private IBinder bindInternal(int uid, Intent intent) throws Exception { ServiceRecord s = mServices.get(name); if (s == null) { - Class clz = ContextUtils.context.getClassLoader().loadClass(name.getClassName()); + Class clz = mContext.getClassLoader().loadClass(name.getClassName()); Constructor ctor = clz.getDeclaredConstructor(); ctor.setAccessible(true); - HiddenAPIs.attachBaseContext(ctor.newInstance(), ContextUtils.context); + HiddenAPIs.attachBaseContext(ctor.newInstance(), mContext); // RootService should be registered after attachBaseContext s = mServices.get(name); diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/utils/ContextUtils.java b/app/src/main/java/io/github/muntashirakon/AppManager/utils/ContextUtils.java index 7a58e4e243a..949dfccb8fc 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/utils/ContextUtils.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/utils/ContextUtils.java @@ -9,6 +9,9 @@ import android.os.Build; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.jetbrains.annotations.Contract; import java.util.Objects; @@ -16,32 +19,38 @@ public final class ContextUtils { public static final String TAG = ContextUtils.class.getSimpleName(); @SuppressLint("StaticFieldLeak") - public static Context context; + public static Context rootContext; + @SuppressLint("StaticFieldLeak") + private static Context sContext; @SuppressLint({"PrivateApi", "RestrictedApi"}) + @NonNull public static Context getContext() { - if (context == null) { + if (sContext == null) { // Fetching ActivityThread on the main thread is no longer required on API 18+ // See: https://cs.android.com/android/platform/frameworks/base/+/66a017b63461a22842b3678c9520f803d5ddadfc try { Context c = (Context) Class.forName("android.app.ActivityThread") .getMethod("currentApplication") .invoke(null); - context = getContextImpl(Objects.requireNonNull(c)); + sContext = getContextImpl(Objects.requireNonNull(c)); } catch (Exception e) { // Shall never happen throw new RuntimeException(e); } } - return context; + return sContext; } + @Contract("!null -> !null") public static Context getDeContext(Context context) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? context.createDeviceProtectedStorageContext() : context; } - public static Context getContextImpl(Context context) { + @Contract("!null -> !null") + @Nullable + public static Context getContextImpl(@Nullable Context context) { while (context instanceof ContextWrapper) { context = ((ContextWrapper) context).getBaseContext(); }