Merge changes I4054d6f4,Ib14e9a93,Iafbe6d51

* changes:
  CpuStats - Do not write debug entries to dump output
  Set ThreadLocalWorkSource when delivering Alarms
  Add WorkSource.getAttributionUid()
This commit is contained in:
TreeHugger Robot
2019-01-22 23:14:25 +00:00
committed by Android (Google) Code Review
6 changed files with 148 additions and 90 deletions

View File

@@ -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

View File

@@ -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))

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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++;
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);
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++;
} 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;
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());
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;
}
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;
}
} 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) {

View File

@@ -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,