Merge change 5196 into donut
* changes:
Modify the IBackupTransport API to support bulk restore operations. Change the BackupManagerService and LocalTransport to support the new API.
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.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 @@
return;
}
+ ParcelFileDescriptor fd = null;
+
String cmd = nextArg();
if ("start".equals(cmd)) {
start = true;
@@ -455,6 +460,16 @@
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 @@
}
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 @@
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 @@
}
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 @@
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.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 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 @@
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 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 @@
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 @@
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.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 @@
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 @@
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 @@
// 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.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 @@
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/content/Intent.java b/core/java/android/content/Intent.java
index 609fa74..6fe5506 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1578,6 +1578,16 @@
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
+ /**
+ * @hide
+ * TODO: This will be unhidden in a later CL.
+ * Broadcast Action: The TextToSpeech synthesizer has completed processing
+ * all of the text in the speech queue.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
+ "android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8fcb4d7..d40ea6b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -21,6 +21,7 @@
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 @@
}
/**
+ * 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 62b4d5e..0d9d2b0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12601,51 +12601,63 @@
}
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) {
+ }
}
}
}