diff options
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 19 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 12 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 31 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 14 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 2 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 4 | ||||
-rw-r--r-- | core/java/android/os/Debug.java | 15 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 90 |
8 files changed, 132 insertions, 55 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 2a4a672..3782136 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -26,10 +26,13 @@ import android.content.ComponentName; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.view.IWindowManager; +import java.io.File; +import java.io.FileNotFoundException; import java.util.Iterator; import java.util.Set; @@ -446,6 +449,8 @@ public class Am { return; } + ParcelFileDescriptor fd = null; + String cmd = nextArg(); if ("start".equals(cmd)) { start = true; @@ -455,6 +460,16 @@ public class Am { showUsage(); return; } + try { + fd = ParcelFileDescriptor.open( + new File(profileFile), + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (FileNotFoundException e) { + System.err.println("Error: Unable to open file: " + profileFile); + return; + } } else if (!"stop".equals(cmd)) { System.err.println("Error: Profile command " + cmd + " not valid"); showUsage(); @@ -462,8 +477,8 @@ public class Am { } try { - if (!mAm.profileControl(process, start, profileFile)) { - System.out.println("PROFILE FAILED on process " + process); + if (!mAm.profileControl(process, start, profileFile, fd)) { + System.err.println("PROFILE FAILED on process " + process); return; } } catch (IllegalArgumentException e) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b6f855a..dfa8139 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -986,7 +986,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String process = data.readString(); boolean start = data.readInt() != 0; String path = data.readString(); - boolean res = profileControl(process, start, path); + ParcelFileDescriptor fd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + boolean res = profileControl(process, start, path, fd); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -2232,7 +2234,7 @@ class ActivityManagerProxy implements IActivityManager } public boolean profileControl(String process, boolean start, - String path) throws RemoteException + String path, ParcelFileDescriptor fd) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2240,6 +2242,12 @@ class ActivityManagerProxy implements IActivityManager data.writeString(process); data.writeInt(start ? 1 : 0); data.writeString(path); + if (fd != null) { + data.writeInt(1); + fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0); reply.readException(); boolean res = reply.readInt() != 0; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 98bd45a..79588ea 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -48,6 +48,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -74,6 +75,7 @@ import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl; import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -1236,6 +1238,11 @@ public final class ActivityThread { String who; } + private static final class ProfilerControlData { + String path; + ParcelFileDescriptor fd; + } + private final class ApplicationThread extends ApplicationThreadNative { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; @@ -1494,8 +1501,11 @@ public final class ActivityThread { } } - public void profilerControl(boolean start, String path) { - queueOrSendMessage(H.PROFILER_CONTROL, path, start ? 1 : 0); + public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) { + ProfilerControlData pcd = new ProfilerControlData(); + pcd.path = path; + pcd.fd = fd; + queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0); } public void setSchedulingGroup(int group) { @@ -1838,7 +1848,7 @@ public final class ActivityThread { handleActivityConfigurationChanged((IBinder)msg.obj); break; case PROFILER_CONTROL: - handleProfilerControl(msg.arg1 != 0, (String)msg.obj); + handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj); break; case CREATE_BACKUP_AGENT: handleCreateBackupAgent((CreateBackupAgentData)msg.obj); @@ -3618,15 +3628,20 @@ public final class ActivityThread { performConfigurationChanged(r.activity, mConfiguration); } - final void handleProfilerControl(boolean start, String path) { + final void handleProfilerControl(boolean start, ProfilerControlData pcd) { if (start) { - File file = new File(path); - file.getParentFile().mkdirs(); try { - Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); + Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(), + 8 * 1024 * 1024, 0); } catch (RuntimeException e) { - Log.w(TAG, "Profiling failed on path " + path + Log.w(TAG, "Profiling failed on path " + pcd.path + " -- can the process access this path?"); + } finally { + try { + pcd.fd.close(); + } catch (IOException e) { + Log.w(TAG, "Failure closing profile fd", e); + } } } else { Debug.stopMethodTracing(); diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 4b64c94..b052c99 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -26,6 +26,7 @@ import android.content.pm.ServiceInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Bundle; +import android.os.Parcelable; import android.os.RemoteException; import android.os.IBinder; import android.os.Parcel; @@ -331,7 +332,9 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); boolean start = data.readInt() != 0; String path = data.readString(); - profilerControl(start, path); + ParcelFileDescriptor fd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + profilerControl(start, path, fd); return true; } @@ -711,11 +714,18 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public void profilerControl(boolean start, String path) throws RemoteException { + public void profilerControl(boolean start, String path, + ParcelFileDescriptor fd) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeInt(start ? 1 : 0); data.writeString(path); + if (fd != null) { + data.writeInt(1); + fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } mRemote.transact(PROFILER_CONTROL_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 66bc85b..3ec7938 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -250,7 +250,7 @@ public interface IActivityManager extends IInterface { // Turn on/off profiling in a particular process. public boolean profileControl(String process, boolean start, - String path) throws RemoteException; + String path, ParcelFileDescriptor fd) throws RemoteException; public boolean shutdown(int timeout) throws RemoteException; diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 029c650..c0bc2a0 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -25,6 +25,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.IBinder; import android.os.IInterface; @@ -92,7 +93,8 @@ public interface IApplicationThread extends IInterface { void scheduleLowMemory() throws RemoteException; void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException; void requestPss() throws RemoteException; - void profilerControl(boolean start, String path) throws RemoteException; + void profilerControl(boolean start, String path, ParcelFileDescriptor fd) + throws RemoteException; void setSchedulingGroup(int group) throws RemoteException; String descriptor = "android.app.IApplicationThread"; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index d9612af..b0fc78e 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -21,6 +21,7 @@ import com.android.internal.util.TypedProperties; import android.util.Config; import android.util.Log; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; @@ -378,6 +379,20 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo } /** + * Like startMethodTracing(String, int, int), but taking an already-opened + * FileDescriptor in which the trace is written. The file name is also + * supplied simply for logging. Makes a dup of the file descriptor. + * + * Not exposed in the SDK unless we are really comfortable with supporting + * this and find it would be useful. + * @hide + */ + public static void startMethodTracing(String traceName, FileDescriptor fd, + int bufferSize, int flags) { + VMDebug.startMethodTracing(traceName, fd, bufferSize, flags); + } + + /** * Determine whether method tracing is currently active. * @hide */ diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cf616b8..5236a91 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -12643,51 +12643,63 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } public boolean profileControl(String process, boolean start, - String path) throws RemoteException { + String path, ParcelFileDescriptor fd) throws RemoteException { - synchronized (this) { - // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to - // its own permission. - if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " - + android.Manifest.permission.SET_ACTIVITY_WATCHER); - } - - ProcessRecord proc = null; - try { - int pid = Integer.parseInt(process); - synchronized (mPidsSelfLocked) { - proc = mPidsSelfLocked.get(pid); + try { + synchronized (this) { + // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to + // its own permission. + if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.SET_ACTIVITY_WATCHER); } - } catch (NumberFormatException e) { - } - - if (proc == null) { - HashMap<String, SparseArray<ProcessRecord>> all - = mProcessNames.getMap(); - SparseArray<ProcessRecord> procs = all.get(process); - if (procs != null && procs.size() > 0) { - proc = procs.valueAt(0); + + if (start && fd == null) { + throw new IllegalArgumentException("null fd"); } - } - - if (proc == null || proc.thread == null) { - throw new IllegalArgumentException("Unknown process: " + process); - } - - boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0")); - if (isSecure) { - if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) { - throw new SecurityException("Process not debuggable: " + proc); + + ProcessRecord proc = null; + try { + int pid = Integer.parseInt(process); + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(pid); + } + } catch (NumberFormatException e) { + } + + if (proc == null) { + HashMap<String, SparseArray<ProcessRecord>> all + = mProcessNames.getMap(); + SparseArray<ProcessRecord> procs = all.get(process); + if (procs != null && procs.size() > 0) { + proc = procs.valueAt(0); + } + } + + if (proc == null || proc.thread == null) { + throw new IllegalArgumentException("Unknown process: " + process); + } + + boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0")); + if (isSecure) { + if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + throw new SecurityException("Process not debuggable: " + proc); + } } - } - try { - proc.thread.profilerControl(start, path); + proc.thread.profilerControl(start, path, fd); + fd = null; return true; - } catch (RemoteException e) { - throw new IllegalStateException("Process disappeared"); + } + } catch (RemoteException e) { + throw new IllegalStateException("Process disappeared"); + } finally { + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + } } } } |