am 9c8dd55a: Fix bug 1829561 ("am profile" with bad filename kills process).
Merge commit '9c8dd55a9d829c29a3feee9469d8c2f27a9f5516'
* commit '9c8dd55a9d829c29a3feee9469d8c2f27a9f5516':
Fix bug 1829561 ("am profile" with bad filename kills process).
This commit is contained in:
committed by
The Android Open Source Project
commit
afed82bca9
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
@@ -377,6 +378,20 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
|
||||
VMDebug.startMethodTracing(pathName, bufferSize, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user