diff options
6 files changed, 150 insertions, 92 deletions
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java index 2299ab2a23ff..76fe560ed902 100644 --- a/core/java/android/os/WorkSource.java +++ b/core/java/android/os/WorkSource.java @@ -140,6 +140,21 @@ public class WorkSource implements Parcelable { return mUids[index]; } + /** + * Return the UID to which this WorkSource should be attributed to, i.e, the UID that + * initiated the work and not the UID performing it. If the WorkSource has no UIDs, returns -1 + * instead. + * + * @hide + */ + public int getAttributionUid() { + if (isEmpty()) { + return -1; + } + + return mNum > 0 ? mUids[0] : mChains.get(0).getAttributionUid(); + } + /** @hide */ @TestApi public String getName(int index) { @@ -912,17 +927,18 @@ public class WorkSource implements Parcelable { /** * Return the UID to which this WorkChain should be attributed to, i.e, the UID that - * initiated the work and not the UID performing it. + * initiated the work and not the UID performing it. Returns -1 if the chain is empty. */ public int getAttributionUid() { - return mUids[0]; + return mSize > 0 ? mUids[0] : -1; } /** * Return the tag associated with the attribution UID. See (@link #getAttributionUid}. + * Returns null if the chain is empty. */ public String getAttributionTag() { - return mTags[0]; + return mTags.length > 0 ? mTags[0] : null; } // TODO: The following three trivial getters are purely for testing and will be removed diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 051a96c39f28..64543522893e 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -53,6 +53,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean DETAILED_TRACKING_DEFAULT = true; public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000; + private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; private static class OverflowBinder extends Binder {} @@ -347,7 +348,7 @@ public class BinderCallsStats implements BinderInternal.Observer { callStat.callingUid = uid; callStat.recordedCallCount = 1; callStat.callCount = 1; - callStat.methodName = "__DEBUG_" + variableName; + callStat.methodName = DEBUG_ENTRY_PREFIX + variableName; callStat.latencyMicros = value; return callStat; } @@ -398,6 +399,10 @@ public class BinderCallsStats implements BinderInternal.Observer { final List<ExportedCallStat> exportedCallStats = getExportedCallStats(); exportedCallStats.sort(BinderCallsStats::compareByCpuDesc); for (ExportedCallStat e : exportedCallStats) { + if (e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) { + // Do not dump debug entries. + continue; + } sb.setLength(0); sb.append(" ") .append(packageMap.mapUid(e.callingUid)) diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java index 9a7fb9f2717b..0f0eeddf9a47 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -37,6 +37,7 @@ import java.util.concurrent.ThreadLocalRandom; * @hide Only for use within the system server. */ public class LooperStats implements Looper.Observer { + public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; private static final int SESSION_POOL_SIZE = 50; @GuardedBy("mLock") @@ -165,7 +166,7 @@ public class LooperStats implements Looper.Observer { } private ExportedEntry createDebugEntry(String variableName, long value) { - final Entry entry = new Entry("__DEBUG_" + variableName); + final Entry entry = new Entry(DEBUG_ENTRY_PREFIX + variableName); entry.messageCount = 1; entry.recordedMessageCount = 1; entry.totalLatencyMicro = value; diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java index 425ab8962307..e94d60c32bfe 100644 --- a/core/tests/coretests/src/android/os/WorkSourceTest.java +++ b/core/tests/coretests/src/android/os/WorkSourceTest.java @@ -341,12 +341,37 @@ public class WorkSourceTest extends TestCase { } public void testGetAttributionId() { - WorkSource ws1 = new WorkSource(); - WorkChain wc = ws1.createWorkChain(); - wc.addNode(100, "tag"); - assertEquals(100, wc.getAttributionUid()); - wc.addNode(200, "tag2"); - assertEquals(100, wc.getAttributionUid()); + WorkSource ws = new WorkSource(); + WorkChain wc1 = ws.createWorkChain(); + wc1.addNode(100, "tag"); + assertEquals(100, wc1.getAttributionUid()); + assertEquals(100, ws.getAttributionUid()); + wc1.addNode(200, "tag2"); + assertEquals(100, wc1.getAttributionUid()); + assertEquals(100, ws.getAttributionUid()); + WorkChain wc2 = ws.createWorkChain(); + wc2.addNode(300, "tag3"); + assertEquals(300, wc2.getAttributionUid()); + assertEquals(100, ws.getAttributionUid()); + } + + public void testGetAttributionIdWithoutWorkChain() { + WorkSource ws1 = new WorkSource(100); + ws1.add(200); + WorkSource ws2 = new WorkSource(); + ws2.add(100); + ws2.add(200); + assertEquals(100, ws1.getAttributionUid()); + assertEquals(100, ws2.getAttributionUid()); + } + + public void testGetAttributionWhenEmpty() { + WorkSource ws = new WorkSource(); + assertEquals(-1, ws.getAttributionUid()); + WorkChain wc = ws.createWorkChain(); + assertEquals(-1, ws.getAttributionUid()); + assertEquals(-1, wc.getAttributionUid()); + assertNull(wc.getAttributionTag()); } public void testGetAttributionTag() { diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 0fa996ed7657..fcd136c65169 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -64,6 +64,7 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.ThreadLocalWorkSource; import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; @@ -1131,23 +1132,23 @@ class AlarmManagerService extends SystemService { final IBinder mListener; final WorkSource mWorkSource; final int mUid; + final int mCreatorUid; final String mTag; final BroadcastStats mBroadcastStats; final FilterStats mFilterStats; final int mAlarmType; - InFlight(AlarmManagerService service, PendingIntent pendingIntent, IAlarmListener listener, - WorkSource workSource, int uid, String alarmPkg, int alarmType, String tag, - long nowELAPSED) { - mPendingIntent = pendingIntent; + InFlight(AlarmManagerService service, Alarm alarm, long nowELAPSED) { + mPendingIntent = alarm.operation; mWhenElapsed = nowELAPSED; - mListener = listener != null ? listener.asBinder() : null; - mWorkSource = workSource; - mUid = uid; - mTag = tag; - mBroadcastStats = (pendingIntent != null) - ? service.getStatsLocked(pendingIntent) - : service.getStatsLocked(uid, alarmPkg); + mListener = alarm.listener != null ? alarm.listener.asBinder() : null; + mWorkSource = alarm.workSource; + mUid = alarm.uid; + mCreatorUid = alarm.creatorUid; + mTag = alarm.statsTag; + mBroadcastStats = (alarm.operation != null) + ? service.getStatsLocked(alarm.operation) + : service.getStatsLocked(alarm.uid, alarm.packageName); FilterStats fs = mBroadcastStats.filterStats.get(mTag); if (fs == null) { fs = new FilterStats(mBroadcastStats, mTag); @@ -1155,7 +1156,7 @@ class AlarmManagerService extends SystemService { } fs.lastTime = nowELAPSED; mFilterStats = fs; - mAlarmType = alarmType; + mAlarmType = alarm.type; } @Override @@ -1165,6 +1166,7 @@ class AlarmManagerService extends SystemService { + ", when=" + mWhenElapsed + ", workSource=" + mWorkSource + ", uid=" + mUid + + ", creatorUid=" + mCreatorUid + ", tag=" + mTag + ", broadcastStats=" + mBroadcastStats + ", filterStats=" + mFilterStats @@ -3811,12 +3813,10 @@ class AlarmManagerService extends SystemService { /** * Attribute blame for a WakeLock. - * @param pi PendingIntent to attribute blame to if ws is null. * @param ws WorkSource to attribute blame. - * @param knownUid attribution uid; < 0 if we need to derive it from the PendingIntent sender + * @param knownUid attribution uid; < 0 values are ignored. */ - void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag, - int knownUid, boolean first) { + void setWakelockWorkSource(WorkSource ws, int knownUid, String tag, boolean first) { try { mWakeLock.setHistoryTag(first ? tag : null); @@ -3825,11 +3825,8 @@ class AlarmManagerService extends SystemService { return; } - final int uid = (knownUid >= 0) - ? knownUid - : ActivityManager.getService().getUidForIntentSender(pi.getTarget()); - if (uid >= 0) { - mWakeLock.setWorkSource(new WorkSource(uid)); + if (knownUid >= 0) { + mWakeLock.setWorkSource(new WorkSource(knownUid)); return; } } catch (Exception e) { @@ -3839,6 +3836,14 @@ class AlarmManagerService extends SystemService { mWakeLock.setWorkSource(null); } + private static int getAlarmAttributionUid(Alarm alarm) { + if (alarm.workSource != null && !alarm.workSource.isEmpty()) { + return alarm.workSource.getAttributionUid(); + } + + return alarm.creatorUid; + } + @VisibleForTesting class AlarmHandler extends Handler { public static final int ALARM_EVENT = 1; @@ -4285,8 +4290,8 @@ class AlarmManagerService extends SystemService { // the next of our alarms is now in flight. reattribute the wakelock. if (mInFlight.size() > 0) { InFlight inFlight = mInFlight.get(0); - setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, - inFlight.mAlarmType, inFlight.mTag, -1, false); + setWakelockWorkSource(inFlight.mWorkSource, inFlight.mCreatorUid, inFlight.mTag, + false); } else { // should never happen mLog.w("Alarm wakelock still held but sent queue empty"); @@ -4369,64 +4374,70 @@ class AlarmManagerService extends SystemService { */ @GuardedBy("mLock") public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) { - if (alarm.operation != null) { - // PendingIntent alarm - mSendCount++; - - try { - alarm.operation.send(getContext(), 0, - mBackgroundIntent.putExtra( - Intent.EXTRA_ALARM_COUNT, alarm.count), - mDeliveryTracker, mHandler, null, - allowWhileIdle ? mIdleOptions : null); - } catch (PendingIntent.CanceledException e) { - if (alarm.repeatInterval > 0) { - // This IntentSender is no longer valid, but this - // is a repeating alarm, so toss it - removeImpl(alarm.operation, null); + final long workSourceToken = ThreadLocalWorkSource.setUid( + getAlarmAttributionUid(alarm)); + try { + if (alarm.operation != null) { + // PendingIntent alarm + mSendCount++; + + try { + alarm.operation.send(getContext(), 0, + mBackgroundIntent.putExtra( + Intent.EXTRA_ALARM_COUNT, alarm.count), + mDeliveryTracker, mHandler, null, + allowWhileIdle ? mIdleOptions : null); + } catch (PendingIntent.CanceledException e) { + if (alarm.repeatInterval > 0) { + // This IntentSender is no longer valid, but this + // is a repeating alarm, so toss it + removeImpl(alarm.operation, null); + } + // No actual delivery was possible, so the delivery tracker's + // 'finished' callback won't be invoked. We also don't need + // to do any wakelock or stats tracking, so we have nothing + // left to do here but go on to the next thing. + mSendFinishCount++; + return; } - // No actual delivery was possible, so the delivery tracker's - // 'finished' callback won't be invoked. We also don't need - // to do any wakelock or stats tracking, so we have nothing - // left to do here but go on to the next thing. - mSendFinishCount++; - return; - } - } else { - // Direct listener callback alarm - mListenerCount++; - - if (RECORD_ALARMS_IN_HISTORY) { - if (alarm.listener == mTimeTickTrigger) { - mTickHistory[mNextTickHistory++] = nowELAPSED; - if (mNextTickHistory >= TICK_HISTORY_DEPTH) { - mNextTickHistory = 0; + } else { + // Direct listener callback alarm + mListenerCount++; + + if (RECORD_ALARMS_IN_HISTORY) { + if (alarm.listener == mTimeTickTrigger) { + mTickHistory[mNextTickHistory++] = nowELAPSED; + if (mNextTickHistory >= TICK_HISTORY_DEPTH) { + mNextTickHistory = 0; + } } } - } - try { - if (DEBUG_LISTENER_CALLBACK) { - Slog.v(TAG, "Alarm to uid=" + alarm.uid - + " listener=" + alarm.listener.asBinder()); - } - alarm.listener.doAlarm(this); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT, - alarm.listener.asBinder()), - mConstants.LISTENER_TIMEOUT); - } catch (Exception e) { - if (DEBUG_LISTENER_CALLBACK) { - Slog.i(TAG, "Alarm undeliverable to listener " - + alarm.listener.asBinder(), e); + try { + if (DEBUG_LISTENER_CALLBACK) { + Slog.v(TAG, "Alarm to uid=" + alarm.uid + + " listener=" + alarm.listener.asBinder()); + } + alarm.listener.doAlarm(this); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT, + alarm.listener.asBinder()), + mConstants.LISTENER_TIMEOUT); + } catch (Exception e) { + if (DEBUG_LISTENER_CALLBACK) { + Slog.i(TAG, "Alarm undeliverable to listener " + + alarm.listener.asBinder(), e); + } + // As in the PendingIntent.CanceledException case, delivery of the + // alarm was not possible, so we have no wakelock or timeout or + // stats management to do. It threw before we posted the delayed + // timeout message, so we're done here. + mListenerFinishCount++; + return; } - // As in the PendingIntent.CanceledException case, delivery of the - // alarm was not possible, so we have no wakelock or timeout or - // stats management to do. It threw before we posted the delayed - // timeout message, so we're done here. - mListenerFinishCount++; - return; } + } finally { + ThreadLocalWorkSource.restore(workSourceToken); } // The alarm is now in flight; now arrange wakelock and stats tracking @@ -4434,15 +4445,11 @@ class AlarmManagerService extends SystemService { Slog.d(TAG, "mBroadcastRefCount -> " + (mBroadcastRefCount + 1)); } if (mBroadcastRefCount == 0) { - setWakelockWorkSource(alarm.operation, alarm.workSource, - alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1, - true); + setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1).sendToTarget(); } - final InFlight inflight = new InFlight(AlarmManagerService.this, - alarm.operation, alarm.listener, alarm.workSource, alarm.uid, - alarm.packageName, alarm.type, alarm.statsTag, nowELAPSED); + final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED); mInFlight.add(inflight); mBroadcastRefCount++; if (allowWhileIdle) { diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java index cee98c10c7f7..4a8706e7090f 100644 --- a/services/core/java/com/android/server/LooperStatsService.java +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -122,6 +122,10 @@ public class LooperStatsService extends Binder { "exception_count")); pw.println(header); for (LooperStats.ExportedEntry entry : entries) { + if (entry.messageName.startsWith(LooperStats.DEBUG_ENTRY_PREFIX)) { + // Do not dump debug entries. + continue; + } pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", packageMap.mapUid(entry.workSourceUid), entry.threadName, |