adpf: Use one client token per process for all hint sessions

So it doesn't leak when gc is delayed in service process.

Update HintManagerService to allow multiple sessions tied to the same
token.

Bug: 218129784
Test: chrome no longer gets killed
Change-Id: I67a66041cc67d01e4cfcd3ded303a1bed6050f60
This commit is contained in:
Bo Liu
2022-02-17 16:47:32 -05:00
parent 4d897c6ad0
commit 9acc558c29
2 changed files with 47 additions and 17 deletions

View File

@@ -48,6 +48,7 @@ private:
static APerformanceHintManager* create(sp<IHintManager> iHintManager);
sp<IHintManager> mHintManager;
const sp<IBinder> mToken = sp<BBinder>::make();
const int64_t mPreferredRateNanos;
};
@@ -119,11 +120,10 @@ APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manage
APerformanceHintSession* APerformanceHintManager::createSession(
const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
sp<IBinder> token = sp<BBinder>::make();
std::vector<int32_t> tids(threadIds, threadIds + size);
sp<IHintSession> session;
binder::Status ret =
mHintManager->createHintSession(token, tids, initialTargetWorkDurationNanos, &session);
mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
if (!ret.isOk() || !session) {
return nullptr;
}

View File

@@ -27,6 +27,7 @@ import android.os.IHintSession;
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -51,8 +52,13 @@ public final class HintManagerService extends SystemService {
private static final boolean DEBUG = false;
@VisibleForTesting final long mHintSessionPreferredRate;
// Multi-levle map storing all active AppHintSessions.
// First level is keyed by the UID of the client process creating the session.
// Second level is keyed by an IBinder passed from client process. This is used to observe
// when the process exits. The client generally uses the same IBinder object across multiple
// sessions, so the value is a set of AppHintSessions.
@GuardedBy("mLock")
private final ArrayMap<Integer, ArrayMap<IBinder, AppHintSession>> mActiveSessions;
private final ArrayMap<Integer, ArrayMap<IBinder, ArraySet<AppHintSession>>> mActiveSessions;
/** Lock to protect HAL handles and listen list. */
private final Object mLock = new Object();
@@ -201,13 +207,16 @@ public final class HintManagerService extends SystemService {
public void onUidGone(int uid, boolean disabled) {
FgThread.getHandler().post(() -> {
synchronized (mLock) {
ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(uid);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(uid);
if (tokenMap == null) {
return;
}
for (int i = tokenMap.size() - 1; i >= 0; i--) {
// Will remove the session from tokenMap
tokenMap.valueAt(i).close();
ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(i);
for (int j = sessionSet.size() - 1; j >= 0; j--) {
sessionSet.valueAt(j).close();
}
}
mProcStatesCache.delete(uid);
}
@@ -231,12 +240,14 @@ public final class HintManagerService extends SystemService {
FgThread.getHandler().post(() -> {
synchronized (mLock) {
mProcStatesCache.put(uid, procState);
ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(uid);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(uid);
if (tokenMap == null) {
return;
}
for (AppHintSession s : tokenMap.values()) {
s.onProcStateChanged();
for (ArraySet<AppHintSession> sessionSet : tokenMap.values()) {
for (AppHintSession s : sessionSet) {
s.onProcStateChanged();
}
}
}
});
@@ -305,17 +316,25 @@ public final class HintManagerService extends SystemService {
long halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid, callingUid,
tids, durationNanos);
if (halSessionPtr == 0) return null;
if (halSessionPtr == 0) {
return null;
}
AppHintSession hs = new AppHintSession(callingUid, callingTgid, tids, token,
halSessionPtr, durationNanos);
synchronized (mLock) {
ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(callingUid);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.get(callingUid);
if (tokenMap == null) {
tokenMap = new ArrayMap<>(1);
mActiveSessions.put(callingUid, tokenMap);
}
tokenMap.put(token, hs);
ArraySet<AppHintSession> sessionSet = tokenMap.get(token);
if (sessionSet == null) {
sessionSet = new ArraySet<>(1);
tokenMap.put(token, sessionSet);
}
sessionSet.add(hs);
return hs;
}
} finally {
@@ -339,10 +358,14 @@ public final class HintManagerService extends SystemService {
pw.println("Active Sessions:");
for (int i = 0; i < mActiveSessions.size(); i++) {
pw.println("Uid " + mActiveSessions.keyAt(i).toString() + ":");
ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.valueAt(i);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.valueAt(i);
for (int j = 0; j < tokenMap.size(); j++) {
pw.println(" Session " + j + ":");
tokenMap.valueAt(j).dump(pw, " ");
ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(j);
for (int k = 0; k < sessionSet.size(); ++k) {
pw.println(" Session:");
sessionSet.valueAt(k).dump(pw, " ");
}
}
}
}
@@ -432,11 +455,18 @@ public final class HintManagerService extends SystemService {
mNativeWrapper.halCloseHintSession(mHalSessionPtr);
mHalSessionPtr = 0;
mToken.unlinkToDeath(this, 0);
ArrayMap<IBinder, AppHintSession> tokenMap = mActiveSessions.get(mUid);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(mUid);
if (tokenMap == null) {
Slogf.w(TAG, "UID %d is note present in active session map", mUid);
Slogf.w(TAG, "UID %d is not present in active session map", mUid);
return;
}
tokenMap.remove(mToken);
ArraySet<AppHintSession> sessionSet = tokenMap.get(mToken);
if (sessionSet == null) {
Slogf.w(TAG, "Token %s is not present in token map", mToken.toString());
return;
}
sessionSet.remove(this);
if (sessionSet.isEmpty()) tokenMap.remove(mToken);
if (tokenMap.isEmpty()) mActiveSessions.remove(mUid);
}
}