Add binder transaction tracking.
Add the ability to am to be able to track binder transact calls. This
will help us diagnose excessive IPC calls.
This CL adds the trace-ip command to am. The usage is,
To start binder transaction tracking,
am trace-ipc start
To stop tracking and dump the data to a file,
am trace-ipc stop --dump-file <FILE>
Bug: 21398706
Change-Id: Ic0c9b3be757dd0662a2750a0d8447e2a5ef1fa90
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bf3b455..9f01b56 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -202,6 +202,11 @@
" --abi <ABI>: Launch the instrumented process with the selected ABI.\n" +
" This assumes that the process supports the selected ABI.\n" +
"\n" +
+ "am trace-ipc: Trace IPC transactions.\n" +
+ " start: start tracing IPC transactions.\n" +
+ " stop: stop tracing IPC transactions and dump the results to file.\n" +
+ " --dump-file <FILE>: Specify the file the trace should be dumped to.\n" +
+ "\n" +
"am profile: start and stop profiler on a process. The given <PROCESS> argument\n" +
" may be either a process name or pid. Options are:\n" +
" --user <USER_ID> | current: When supplying a process name,\n" +
@@ -365,6 +370,8 @@
runKillAll();
} else if (op.equals("instrument")) {
runInstrument();
+ } else if (op.equals("trace-ipc")) {
+ runTraceIpc();
} else if (op.equals("broadcast")) {
sendBroadcast();
} else if (op.equals("profile")) {
@@ -1097,6 +1104,62 @@
}
}
+ private void runTraceIpc() throws Exception {
+ String op = nextArgRequired();
+ if (op.equals("start")) {
+ runTraceIpcStart();
+ } else if (op.equals("stop")) {
+ runTraceIpcStop();
+ } else {
+ showError("Error: unknown command '" + op + "'");
+ return;
+ }
+ }
+
+ private void runTraceIpcStart() throws Exception {
+ System.out.println("Starting IPC tracing.");
+ mAm.startBinderTracking();
+ }
+
+ private void runTraceIpcStop() throws Exception {
+ String opt;
+ String filename = null;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("--dump-file")) {
+ filename = nextArgRequired();
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+ }
+ if (filename == null) {
+ System.err.println("Error: Specify filename to dump logs to.");
+ return;
+ }
+
+ ParcelFileDescriptor fd = null;
+
+ try {
+ File file = new File(filename);
+ file.delete();
+ fd = openForSystemServer(file,
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ System.err.println("Error: Unable to open file: " + filename);
+ System.err.println("Consider using a file under /data/local/tmp/");
+ return;
+ }
+
+ ;
+ if (!mAm.stopBinderTrackingAndDump(fd)) {
+ throw new AndroidException("STOP TRACE FAILED.");
+ }
+
+ System.out.println("Stopped IPC tracing. Dumping logs to: " + filename);
+ }
+
static void removeWallOption() {
String props = SystemProperties.get("dalvik.vm.extra-opts");
if (props != null && props.contains("-Xprofile:wallclock")) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6ae21eb..07b9ebe 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2554,6 +2554,24 @@
reply.writeInt(res ? 1 : 0);
return true;
}
+
+ case START_BINDER_TRACKING_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean res = startBinderTracking();
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
+ case STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ ParcelFileDescriptor fd = data.readInt() != 0
+ ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
+ boolean res = stopBinderTrackingAndDump(fd);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5505,6 +5523,36 @@
reply.recycle();
}
+ public boolean startBinderTracking() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(START_BINDER_TRACKING_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
+ public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ if (fd != null) {
+ data.writeInt(1);
+ fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
@Override
public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e21c04a..c95f876 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -445,6 +445,7 @@
IInstrumentationWatcher instrumentationWatcher;
IUiAutomationConnection instrumentationUiAutomationConnection;
int debugMode;
+ boolean enableBinderTracking;
boolean enableOpenGlTrace;
boolean restrictedBackupMode;
boolean persistent;
@@ -770,7 +771,8 @@
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
- boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
+ boolean enableBinderTracking, boolean enableOpenGlTrace,
+ boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) {
@@ -827,6 +829,7 @@
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
+ data.enableBinderTracking = enableBinderTracking;
data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
@@ -1223,6 +1226,19 @@
StrictMode.onCleartextNetworkDetected(firstPacket);
}
}
+
+ @Override
+ public void startBinderTracking() {
+ sendMessage(H.START_BINDER_TRACKING, null);
+ }
+
+ @Override
+ public void stopBinderTrackingAndDump(FileDescriptor fd) {
+ try {
+ sendMessage(H.STOP_BINDER_TRACKING_AND_DUMP, ParcelFileDescriptor.dup(fd));
+ } catch (IOException e) {
+ }
+ }
}
private class H extends Handler {
@@ -1276,6 +1292,8 @@
public static final int CANCEL_VISIBLE_BEHIND = 147;
public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
+ public static final int START_BINDER_TRACKING = 150;
+ public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1558,6 +1576,12 @@
case ENTER_ANIMATION_COMPLETE:
handleEnterAnimationComplete((IBinder) msg.obj);
break;
+ case START_BINDER_TRACKING:
+ handleStartBinderTracking();
+ break;
+ case STOP_BINDER_TRACKING_AND_DUMP:
+ handleStopBinderTrackingAndDump((ParcelFileDescriptor) msg.obj);
+ break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
@@ -2663,6 +2687,20 @@
}
}
+ private void handleStartBinderTracking() {
+ Binder.enableTracing();
+ }
+
+ private void handleStopBinderTrackingAndDump(ParcelFileDescriptor fd) {
+ try {
+ Binder.disableTracing();
+ Binder.getTransactionTracker().writeTracesToFile(fd);
+ } finally {
+ IoUtils.closeQuietly(fd);
+ Binder.getTransactionTracker().clearTraces();
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
@@ -4583,8 +4621,11 @@
}
// Allow application-generated systrace messages if we're debuggable.
- boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- Trace.setAppTracingAllowed(appTracingAllowed);
+ boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ Trace.setAppTracingAllowed(isAppDebuggable);
+ if (isAppDebuggable && data.enableBinderTracking) {
+ Binder.enableTracing();
+ }
/**
* Initialize the default http proxy in this process for the reasons we set the time zone.
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 1461380..372fdaa 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -288,6 +288,7 @@
IUiAutomationConnection uiAutomationConnection =
IUiAutomationConnection.Stub.asInterface(binder);
int testMode = data.readInt();
+ boolean enableBinderTracking = data.readInt() != 0;
boolean openGlTrace = data.readInt() != 0;
boolean restrictedBackupMode = (data.readInt() != 0);
boolean persistent = (data.readInt() != 0);
@@ -296,8 +297,8 @@
HashMap<String, IBinder> services = data.readHashMap(null);
Bundle coreSettings = data.readBundle();
bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
- testWatcher, uiAutomationConnection, testMode, openGlTrace,
- restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
+ testWatcher, uiAutomationConnection, testMode, enableBinderTracking,
+ openGlTrace, restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
return true;
}
@@ -690,6 +691,28 @@
reply.writeNoException();
return true;
}
+
+ case START_BINDER_TRACKING_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ startBinderTracking();
+ return true;
+ }
+
+ case STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ if (fd != null) {
+ stopBinderTrackingAndDump(fd.getFileDescriptor());
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ }
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -980,12 +1003,12 @@
}
public final void bindApplication(String packageName, ApplicationInfo info,
- List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
- Bundle testArgs, IInstrumentationWatcher testWatcher,
- IUiAutomationConnection uiAutomationConnection, int debugMode,
- boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
- Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
- Bundle coreSettings) throws RemoteException {
+ List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
+ Bundle testArgs, IInstrumentationWatcher testWatcher,
+ IUiAutomationConnection uiAutomationConnection, int debugMode,
+ boolean enableBinderTracking, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
+ Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
+ Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
@@ -1007,6 +1030,7 @@
data.writeStrongInterface(testWatcher);
data.writeStrongInterface(uiAutomationConnection);
data.writeInt(debugMode);
+ data.writeInt(enableBinderTracking ? 1 : 0);
data.writeInt(openGlTrace ? 1 : 0);
data.writeInt(restrictedBackupMode ? 1 : 0);
data.writeInt(persistent ? 1 : 0);
@@ -1396,4 +1420,23 @@
mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public void startBinderTracking() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ mRemote.transact(START_BINDER_TRACKING_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
+
+ @Override
+ public void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ mRemote.transact(STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9311e5e..cbbe845 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -508,6 +508,13 @@
public boolean setProcessMemoryTrimLevel(String process, int uid, int level)
throws RemoteException;
+ // Start Binder transaction tracking for all applications.
+ public boolean startBinderTracking() throws RemoteException;
+
+ // Stop Binder transaction tracking for all applications and dump trace data to the given file
+ // descriptor.
+ public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -851,4 +858,7 @@
int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297;
int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298;
+
+ int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 299;
+ int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 300;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 185578f..5c4d359 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -95,9 +95,10 @@
void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
ComponentName testName, ProfilerInfo profilerInfo, Bundle testArguments,
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
- int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
- Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
- Bundle coreSettings) throws RemoteException;
+ int debugMode, boolean enableBinderTracking, boolean openGlTrace,
+ boolean restrictedBackupMode, boolean persistent, Configuration config,
+ CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings)
+ throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleSuicide() throws RemoteException;
void scheduleConfigurationChanged(Configuration config) throws RemoteException;
@@ -148,6 +149,8 @@
void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled) throws RemoteException;
void scheduleEnterAnimationComplete(IBinder token) throws RemoteException;
void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
+ void startBinderTracking() throws RemoteException;
+ void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -206,4 +209,6 @@
int BACKGROUND_VISIBLE_BEHIND_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54;
int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55;
+ int START_BINDER_TRACKING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+56;
+ int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+57;
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 64562a4..cfa6164 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -74,11 +74,62 @@
*/
private static String sDumpDisabled = null;
+ /**
+ * Global transaction tracker instance for this process.
+ */
+ private static TransactionTracker sTransactionTracker = null;
+
+ // Transaction tracking code.
+
+ /**
+ * Flag indicating whether we should be tracing transact calls.
+ *
+ */
+ private static boolean sTracingEnabled = false;
+
+ /**
+ * Enable Binder IPC tracing.
+ *
+ * @hide
+ */
+ public static void enableTracing() {
+ sTracingEnabled = true;
+ };
+
+ /**
+ * Disable Binder IPC tracing.
+ *
+ * @hide
+ */
+ public static void disableTracing() {
+ sTracingEnabled = false;
+ }
+
+ /**
+ * Check if binder transaction tracing is enabled.
+ *
+ * @hide
+ */
+ public static boolean isTracingEnabled() {
+ return sTracingEnabled;
+ }
+
+ /**
+ * Get the binder transaction tracker for this process.
+ *
+ * @hide
+ */
+ public synchronized static TransactionTracker getTransactionTracker() {
+ if (sTransactionTracker == null)
+ sTransactionTracker = new TransactionTracker();
+ return sTransactionTracker;
+ }
+
/* mObject is used by native code, do not remove or rename */
private long mObject;
private IInterface mOwner;
private String mDescriptor;
-
+
/**
* Return the ID of the process that sent you the current transaction
* that is being processed. This pid can be used with higher-level
@@ -381,6 +432,7 @@
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
+
if (data != null) {
data.setDataPosition(0);
}
@@ -500,6 +552,7 @@
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
+ if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
return transactNative(code, data, reply, flags);
}
diff --git a/core/java/android/os/TransactionTracker.java b/core/java/android/os/TransactionTracker.java
new file mode 100644
index 0000000..77f3e02
--- /dev/null
+++ b/core/java/android/os/TransactionTracker.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 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 android.os;
+
+import android.util.Log;
+import android.util.Size;
+import com.android.internal.util.FastPrintWriter;
+
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class used to track binder transactions. It indexes the transactions by the stack trace.
+ *
+ * @hide
+ */
+public class TransactionTracker {
+ private Map<String, Long> mTraces;
+
+ private void resetTraces() {
+ synchronized (this) {
+ mTraces = new HashMap<String, Long>();
+ }
+ }
+
+ TransactionTracker() {
+ resetTraces();
+ }
+
+ public void addTrace() {
+ String trace = Log.getStackTraceString(new Throwable());
+ synchronized (this) {
+ if (mTraces.containsKey(trace)) {
+ mTraces.put(trace, mTraces.get(trace) + 1);
+ } else {
+ mTraces.put(trace, Long.valueOf(1));
+ }
+ }
+ }
+
+ public void writeTracesToFile(ParcelFileDescriptor fd) {
+ if (mTraces.isEmpty()) {
+ return;
+ }
+
+ PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
+ synchronized (this) {
+ for (String trace : mTraces.keySet()) {
+ pw.println("Count: " + mTraces.get(trace));
+ pw.println("Trace: " + trace);
+ pw.println();
+ }
+ }
+ pw.flush();
+ }
+
+ public void clearTraces(){
+ resetTraces();
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 45dcfd3..db4f395 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -641,6 +641,8 @@
*/
final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
+ private boolean mBinderTransactionTrackingEnabled = false;
+
/**
* Last time we requested PSS data of all processes.
*/
@@ -6042,9 +6044,9 @@
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
- app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
- isRestrictedBackupMode || !normalMode, app.persistent,
- new Configuration(mConfiguration), app.compat,
+ app.instrumentationUiAutomationConnection, testMode,
+ mBinderTransactionTrackingEnabled, enableOpenGlTrace, isRestrictedBackupMode
+ || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
@@ -20288,6 +20290,104 @@
return info;
}
+ private boolean processSanityChecksLocked(ProcessRecord process) {
+ if (process == null || process.thread == null) {
+ return false;
+ }
+
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((process.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean startBinderTracking() throws RemoteException {
+ synchronized (this) {
+ mBinderTransactionTrackingEnabled = true;
+ // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
+ // permission (same as profileControl).
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ for (int i = 0; i < mLruProcesses.size(); i++) {
+ ProcessRecord process = mLruProcesses.get(i);
+ if (!processSanityChecksLocked(process)) {
+ continue;
+ }
+ try {
+ process.thread.startBinderTracking();
+ } catch (RemoteException e) {
+ Log.v(TAG, "Process disappared");
+ }
+ }
+ return true;
+ }
+ }
+
+ public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException {
+ try {
+ synchronized (this) {
+ mBinderTransactionTrackingEnabled = false;
+ // TODO: hijacking SET_ACTIVITY_WATCHER, but should be changed to its own
+ // permission (same as profileControl).
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ if (fd == null) {
+ throw new IllegalArgumentException("null fd");
+ }
+
+ PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
+ pw.println("Binder transaction traces for all processes.\n");
+ for (ProcessRecord process : mLruProcesses) {
+ if (!processSanityChecksLocked(process)) {
+ continue;
+ }
+
+ pw.println("Traces for process: " + process.processName);
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ process.thread.stopBinderTrackingAndDump(
+ tp.getWriteFd().getFileDescriptor());
+ tp.go(fd.getFileDescriptor());
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println("Failure while dumping IPC traces from " + process +
+ ". Exception: " + e);
+ pw.flush();
+ } catch (RemoteException e) {
+ pw.println("Got a RemoteException while dumping IPC traces from " +
+ process + ". Exception: " + e);
+ pw.flush();
+ }
+ }
+ fd = null;
+ return true;
+ }
+ } finally {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
private final class LocalService extends ActivityManagerInternal {
@Override
public void onWakefulnessChanged(int wakefulness) {