Skip to content

Commit

Permalink
[Refactor] Fix launching privileged service on OnePlus devices
Browse files Browse the repository at this point in the history
Thanks: John Wu
Signed-off-by: Muntashir Al-Islam <[email protected]>
  • Loading branch information
MuntashirAkon committed Nov 12, 2023
1 parent 4e49366 commit c770c41
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public ComponentName getComponentName() {
@SuppressLint("RestrictedApi")
@Override
public final Context getApplicationContext() {
return ContextUtils.getContext();
return ContextUtils.rootContext;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -67,11 +68,13 @@ public static RootServiceServer getInstance(Context context) {
private final Map<ComponentName, ServiceRecord> mServices = new ArrayMap<>();
private final SparseArray<ClientProcess> 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) {
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,48 @@
import android.os.Build;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.jetbrains.annotations.Contract;

import java.util.Objects;

// Copyright 2020 John "topjohnwu" Wu
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();
}
Expand Down

0 comments on commit c770c41

Please sign in to comment.