import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.ProgressReporter;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import android.app.IUidObserver;
import android.app.IUserSwitchObserver;
import android.app.Instrumentation;
-import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
// so that dispatch of foreground broadcasts gets precedence.
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
+ BroadcastStats mLastBroadcastStats;
+ BroadcastStats mCurBroadcastStats;
+
BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
boolean dumpAll = false;
boolean dumpClient = false;
+ boolean dumpCheckin = false;
+ boolean dumpCheckinFormat = false;
String dumpPackage = null;
int opti = 0;
return;
}
dumpClient = true;
+ } else if ("--checkin".equals(opt)) {
+ dumpCheckin = dumpCheckinFormat = true;
+ } else if ("-C".equals(opt)) {
+ dumpCheckinFormat = true;
} else if ("-h".equals(opt)) {
ActivityManagerShellCommand.dumpHelp(pw, true);
return;
synchronized (this) {
dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
}
+ } else if ("broadcast-stats".equals(cmd)) {
+ String[] newArgs;
+ String name;
+ if (opti >= args.length) {
+ name = null;
+ newArgs = EMPTY_STRING_ARRAY;
+ } else {
+ dumpPackage = args[opti];
+ opti++;
+ newArgs = new String[args.length - opti];
+ if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
+ args.length - opti);
+ }
+ synchronized (this) {
+ dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+ }
} else if ("intents".equals(cmd) || "i".equals(cmd)) {
String[] newArgs;
String name;
}
// No piece of data specified, dump everything.
- if (dumpClient) {
+ if (dumpCheckinFormat) {
+ dumpBroadcastStatsCheckinLocked(fd, pw, args, opti, dumpCheckin, dumpPackage);
+ } else if (dumpClient) {
ActiveServices.ServiceDumper sdumper;
synchronized (this) {
dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
+ if (dumpAll || dumpPackage != null) {
+ dumpBroadcastStatsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ }
dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
+ if (dumpAll || dumpPackage != null) {
+ dumpBroadcastStatsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ }
dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
}
}
+ void dumpBroadcastStatsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage) {
+ if (mCurBroadcastStats == null) {
+ return;
+ }
+
+ pw.println("ACTIVITY MANAGER BROADCAST STATS STATE (dumpsys activity broadcast-stats)");
+ final long now = SystemClock.elapsedRealtime();
+ if (mLastBroadcastStats != null) {
+ pw.print(" Last stats (from ");
+ TimeUtils.formatDuration(mLastBroadcastStats.mStartRealtime, now, pw);
+ pw.print(" to ");
+ TimeUtils.formatDuration(mLastBroadcastStats.mEndRealtime, now, pw);
+ pw.print(", ");
+ TimeUtils.formatDuration(mLastBroadcastStats.mEndUptime
+ - mLastBroadcastStats.mStartUptime, pw);
+ pw.println(" uptime):");
+ if (!mLastBroadcastStats.dumpStats(pw, " ", dumpPackage)) {
+ pw.println(" (nothing)");
+ }
+ pw.println();
+ }
+ pw.print(" Current stats (from ");
+ TimeUtils.formatDuration(mCurBroadcastStats.mStartRealtime, now, pw);
+ pw.print(" to now, ");
+ TimeUtils.formatDuration(SystemClock.uptimeMillis()
+ - mCurBroadcastStats.mStartUptime, pw);
+ pw.println(" uptime):");
+ if (!mCurBroadcastStats.dumpStats(pw, " ", dumpPackage)) {
+ pw.println(" (nothing)");
+ }
+ }
+
+ void dumpBroadcastStatsCheckinLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean fullCheckin, String dumpPackage) {
+ if (mCurBroadcastStats == null) {
+ return;
+ }
+
+ if (mLastBroadcastStats != null) {
+ mLastBroadcastStats.dumpCheckinStats(pw, dumpPackage);
+ if (fullCheckin) {
+ mLastBroadcastStats = null;
+ return;
+ }
+ }
+ mCurBroadcastStats.dumpCheckinStats(pw, dumpPackage);
+ if (fullCheckin) {
+ mCurBroadcastStats = null;
+ }
+ }
+
void dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep;
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
+ } else {
+ // There was nobody interested in the broadcast, but we still want to record
+ // that it happened.
+ if (intent.getComponent() == null && intent.getPackage() == null
+ && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
+ // This was an implicit broadcast... let's record it for posterity.
+ addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
+ }
}
return ActivityManager.BROADCAST_SUCCESS;
}
+ final void addBroadcastStatLocked(String action, String srcPackage, int receiveCount,
+ int skipCount, long dispatchTime) {
+ final long now = SystemClock.elapsedRealtime();
+ if (mCurBroadcastStats == null ||
+ (mCurBroadcastStats.mStartRealtime +(24*60*60*1000) < now)) {
+ mLastBroadcastStats = mCurBroadcastStats;
+ if (mLastBroadcastStats != null) {
+ mLastBroadcastStats.mEndRealtime = SystemClock.elapsedRealtime();
+ mLastBroadcastStats.mEndUptime = SystemClock.uptimeMillis();
+ }
+ mCurBroadcastStats = new BroadcastStats();
+ }
+ mCurBroadcastStats.addBroadcast(action, srcPackage, receiveCount, skipCount, dispatchTime);
+ }
+
final Intent verifyBroadcastLocked(Intent intent) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+public final class BroadcastStats {
+ final long mStartRealtime;
+ final long mStartUptime;
+ long mEndRealtime;
+ long mEndUptime;
+ final ArrayMap<String, ActionEntry> mActions = new ArrayMap<>();
+
+ static final Comparator<ActionEntry> ACTIONS_COMPARATOR = new Comparator<ActionEntry>() {
+ @Override public int compare(ActionEntry o1, ActionEntry o2) {
+ if (o1.mTotalDispatchTime < o2.mTotalDispatchTime) {
+ return -1;
+ }
+ if (o1.mTotalDispatchTime > o2.mTotalDispatchTime) {
+ return 1;
+ }
+ return 0;
+ }
+ };
+
+ static final class ActionEntry {
+ final String mAction;
+ final ArrayMap<String, PackageEntry> mPackages = new ArrayMap<>();
+ int mReceiveCount;
+ int mSkipCount;
+ long mTotalDispatchTime;
+ long mMaxDispatchTime;
+
+ ActionEntry(String action) {
+ mAction = action;
+ }
+ }
+
+ static final class PackageEntry {
+ int mSendCount;
+ }
+
+ public BroadcastStats() {
+ mStartRealtime = SystemClock.elapsedRealtime();
+ mStartUptime = SystemClock.uptimeMillis();
+ }
+
+ public void addBroadcast(String action, String srcPackage, int receiveCount,
+ int skipCount, long dispatchTime) {
+ ActionEntry ae = mActions.get(action);
+ if (ae == null) {
+ ae = new ActionEntry(action);
+ mActions.put(action, ae);
+ }
+ ae.mReceiveCount += receiveCount;
+ ae.mSkipCount += skipCount;
+ ae.mTotalDispatchTime += dispatchTime;
+ if (ae.mMaxDispatchTime < dispatchTime) {
+ ae.mMaxDispatchTime = dispatchTime;
+ }
+ PackageEntry pe = ae.mPackages.get(srcPackage);
+ if (pe == null) {
+ pe = new PackageEntry();
+ ae.mPackages.put(srcPackage, pe);
+ }
+ pe.mSendCount++;
+ }
+
+ public boolean dumpStats(PrintWriter pw, String prefix, String dumpPackage) {
+ boolean printedSomething = false;
+ ArrayList<ActionEntry> actions = new ArrayList<>(mActions.size());
+ for (int i=mActions.size()-1; i>=0; i--) {
+ actions.add(mActions.valueAt(i));
+ }
+ Collections.sort(actions, ACTIONS_COMPARATOR);
+ for (int i=actions.size()-1; i>=0; i--) {
+ ActionEntry ae = actions.get(i);
+ if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
+ continue;
+ }
+ printedSomething = true;
+ pw.print(prefix);
+ pw.print(ae.mAction);
+ pw.println(":");
+ pw.print(prefix);
+ pw.print(" Number received: ");
+ pw.print(ae.mReceiveCount);
+ pw.print(", skipped: ");
+ pw.println(ae.mSkipCount);
+ pw.print(prefix);
+ pw.print(" Total dispatch time: ");
+ TimeUtils.formatDuration(ae.mTotalDispatchTime, pw);
+ pw.print(", max: ");
+ TimeUtils.formatDuration(ae.mMaxDispatchTime, pw);
+ pw.println();
+ for (int j=ae.mPackages.size()-1; j>=0; j--) {
+ pw.print(prefix);
+ pw.print(" Package ");
+ pw.print(ae.mPackages.keyAt(j));
+ pw.print(": ");
+ PackageEntry pe = ae.mPackages.valueAt(j);
+ pw.print(pe.mSendCount);
+ pw.println(" times");
+ }
+ }
+ return printedSomething;
+ }
+
+ public void dumpCheckinStats(PrintWriter pw, String dumpPackage) {
+ pw.print("broadcast-stats,1,");
+ pw.print(mStartRealtime);
+ pw.print(",");
+ pw.print(mEndRealtime == 0 ? SystemClock.elapsedRealtime() : mEndRealtime);
+ pw.print(",");
+ pw.println((mEndUptime == 0 ? SystemClock.uptimeMillis() : mEndUptime) - mStartUptime);
+ for (int i=mActions.size()-1; i>=0; i--) {
+ ActionEntry ae = mActions.valueAt(i);
+ if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
+ continue;
+ }
+ pw.print("a,");
+ pw.print(mActions.keyAt(i));
+ pw.print(",");
+ pw.print(ae.mReceiveCount);
+ pw.print(",");
+ pw.print(ae.mSkipCount);
+ pw.print(",");
+ pw.print(ae.mTotalDispatchTime);
+ pw.print(",");
+ pw.print(ae.mMaxDispatchTime);
+ pw.println();
+ for (int j=ae.mPackages.size()-1; j>=0; j--) {
+ pw.print("p,");
+ pw.print(ae.mPackages.keyAt(j));
+ PackageEntry pe = ae.mPackages.valueAt(j);
+ pw.print(",");
+ pw.print(pe.mSendCount);
+ pw.println();
+ }
+ }
+ }
+}