HintManagerService: allow application to create session for non-calling-processes.
Currently isolated processed cannot use HintManagerService due to
sepolicy. This change is to allow application to create sessions for its
other isolated/non-isolated processes.
Bug: 191703385
Test: atest HintManagerServiceTest
Signed-off-by: Wei Wang <wvw@google.com>
Change-Id: If784a7f620edcf8d5ca9b7fb8dfa2358269f1eac
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index fc7628c..6014d0c 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.power.hint;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.IUidObserver;
import android.content.Context;
import android.os.Binder;
@@ -33,12 +34,16 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.utils.Slogf;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
/** An hint service implementation that runs in System Server process. */
public final class HintManagerService extends SystemService {
@@ -56,6 +61,8 @@
private final NativeWrapper mNativeWrapper;
+ private final ActivityManagerInternal mAmInternal;
+
@VisibleForTesting final IHintManager.Stub mService = new BinderService();
public HintManagerService(Context context) {
@@ -70,6 +77,8 @@
mNativeWrapper.halInit();
mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
mUidObserver = new UidObserver();
+ mAmInternal = Objects.requireNonNull(
+ LocalServices.getService(ActivityManagerInternal.class));
}
@VisibleForTesting
@@ -85,7 +94,7 @@
@Override
public void onStart() {
- publishBinderService(Context.PERFORMANCE_HINT_SERVICE, mService, /* allowIsolated= */ true);
+ publishBinderService(Context.PERFORMANCE_HINT_SERVICE, mService);
}
@Override
@@ -243,12 +252,30 @@
return mService;
}
- private boolean checkTidValid(int tgid, int [] tids) {
- // Make sure all tids belongs to the same process.
+ private boolean checkTidValid(int uid, int tgid, int [] tids) {
+ // Make sure all tids belongs to the same UID (including isolated UID),
+ // tids can belong to different application processes.
+ List<Integer> eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+ if (eligiblePids == null) {
+ eligiblePids = new ArrayList<>();
+ }
+ eligiblePids.add(tgid);
+
for (int threadId : tids) {
- if (!Process.isThreadInProcess(tgid, threadId)) {
- return false;
+ final String[] procStatusKeys = new String[] {
+ "Uid:",
+ "Tgid:"
+ };
+ long[] output = new long[procStatusKeys.length];
+ Process.readProcLines("/proc/" + threadId + "/status", procStatusKeys, output);
+ int uidOfThreadId = (int) output[0];
+ int pidOfThreadId = (int) output[1];
+
+ // use PID check for isolated processes, use UID check for non-isolated processes.
+ if (eligiblePids.contains(pidOfThreadId) || uidOfThreadId == uid) {
+ continue;
}
+ return false;
}
return true;
}
@@ -264,27 +291,25 @@
Preconditions.checkArgument(tids.length != 0, "tids should"
+ " not be empty.");
- int uid = Binder.getCallingUid();
- int tid = Binder.getCallingPid();
- int pid = Process.getThreadGroupLeader(tid);
-
+ final int callingUid = Binder.getCallingUid();
+ final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
try {
- if (!checkTidValid(pid, tids)) {
- throw new SecurityException("Some tid doesn't belong to the process");
+ if (!checkTidValid(callingUid, callingTgid, tids)) {
+ throw new SecurityException("Some tid doesn't belong to the application");
}
- long halSessionPtr = mNativeWrapper.halCreateHintSession(pid, uid, tids,
- durationNanos);
+ long halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid, callingUid,
+ tids, durationNanos);
if (halSessionPtr == 0) return null;
- AppHintSession hs = new AppHintSession(uid, pid, tids, token,
+ AppHintSession hs = new AppHintSession(callingUid, callingTgid, tids, token,
halSessionPtr, durationNanos);
synchronized (mLock) {
- ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(uid);
+ ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(callingUid);
if (tokenMap == null) {
tokenMap = new ArrayMap<>(1);
- mActiveSessions.put(uid, tokenMap);
+ mActiveSessions.put(callingUid, tokenMap);
}
tokenMap.put(token, hs);
return hs;
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
index aaf40d7..397770b 100644
--- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
@@ -36,6 +37,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -43,6 +45,7 @@
import android.os.Process;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.android.server.power.hint.HintManagerService.AppHintSession;
import com.android.server.power.hint.HintManagerService.Injector;
import com.android.server.power.hint.HintManagerService.NativeWrapper;
@@ -74,6 +77,7 @@
@Mock private Context mContext;
@Mock private HintManagerService.NativeWrapper mNativeWrapperMock;
+ @Mock private ActivityManagerInternal mAmInternalMock;
private HintManagerService mService;
@@ -86,6 +90,9 @@
eq(DEFAULT_TARGET_DURATION))).thenReturn(1L);
when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_B),
eq(DEFAULT_TARGET_DURATION))).thenReturn(2L);
+ when(mAmInternalMock.getIsolatedProcesses(anyInt())).thenReturn(null);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
}
private HintManagerService createService() {
@@ -105,6 +112,17 @@
}
@Test
+ public void testCreateHintSessionInvalidPid() throws Exception {
+ HintManagerService service = createService();
+ IBinder token = new Binder();
+ // Make sure we throw exception when adding a TID doesn't belong to the processes
+ // In this case, we add `init` PID into the list.
+ assertThrows(SecurityException.class,
+ () -> service.getBinderServiceInstance().createHintSession(token,
+ new int[]{TID, 1}, DEFAULT_TARGET_DURATION));
+ }
+
+ @Test
public void testCreateHintSession() throws Exception {
HintManagerService service = createService();
IBinder token = new Binder();