diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-04-06 20:21:54 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-06 20:21:58 +0000 |
commit | 516460819541e483321ef9156e4093d19f123ecc (patch) | |
tree | e56340f67bb7ae5ce512618146bef9b5f5e5130f | |
parent | b8a330ebe74f01e05681d24129dd1d595dc23207 (diff) | |
parent | d59a5d59df920d743723521a2afed9de1da3373b (diff) | |
download | frameworks_base-516460819541e483321ef9156e4093d19f123ecc.zip frameworks_base-516460819541e483321ef9156e4093d19f123ecc.tar.gz frameworks_base-516460819541e483321ef9156e4093d19f123ecc.tar.bz2 |
Merge "Various fixes and improvements..."
17 files changed, 333 insertions, 58 deletions
diff --git a/api/current.txt b/api/current.txt index d79ccbe..cb63af7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3553,6 +3553,7 @@ package android.app { public class ActivityManager { method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap); method public boolean clearApplicationUserData(); + method public void clearWatchHeapLimit(); method public void dumpPackageState(java.io.FileDescriptor, java.lang.String); method public android.util.Size getAppTaskThumbnailSize(); method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks(); @@ -3579,6 +3580,8 @@ package android.app { method public void moveTaskToFront(int, int); method public void moveTaskToFront(int, int, android.os.Bundle); method public deprecated void restartPackage(java.lang.String); + method public void setWatchHeapLimit(long); + field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT"; field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1 field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0 field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2 @@ -5434,10 +5437,12 @@ package android.app { public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable { ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence); + ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int); method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence); method public int countSynonyms(); method public int describeContents(); method public android.os.Bundle getExtras(); + method public int getIndex(); method public java.lang.CharSequence getLabel(); method public java.lang.CharSequence getSynonymAt(int); method public void setExtras(android.os.Bundle); @@ -28271,6 +28276,7 @@ package android.service.voice { ctor public VoiceInteractionSession(android.content.Context); ctor public VoiceInteractionSession(android.content.Context, android.os.Handler); method public void finish(); + method public android.content.Context getContext(); method public android.view.LayoutInflater getLayoutInflater(); method public android.app.Dialog getWindow(); method public void hide(); diff --git a/api/system-current.txt b/api/system-current.txt index e57eee5..7ef0008 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3641,6 +3641,7 @@ package android.app { public class ActivityManager { method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap); method public boolean clearApplicationUserData(); + method public void clearWatchHeapLimit(); method public void dumpPackageState(java.io.FileDescriptor, java.lang.String); method public android.util.Size getAppTaskThumbnailSize(); method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks(); @@ -3668,6 +3669,8 @@ package android.app { method public void moveTaskToFront(int, int); method public void moveTaskToFront(int, int, android.os.Bundle); method public deprecated void restartPackage(java.lang.String); + method public void setWatchHeapLimit(long); + field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT"; field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1 field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0 field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2 @@ -5525,10 +5528,12 @@ package android.app { public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable { ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence); + ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int); method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence); method public int countSynonyms(); method public int describeContents(); method public android.os.Bundle getExtras(); + method public int getIndex(); method public java.lang.CharSequence getLabel(); method public java.lang.CharSequence getSynonymAt(int); method public void setExtras(android.os.Bundle); @@ -30346,6 +30351,7 @@ package android.service.voice { ctor public VoiceInteractionSession(android.content.Context); ctor public VoiceInteractionSession(android.content.Context, android.os.Handler); method public void finish(); + method public android.content.Context getContext(); method public android.view.LayoutInflater getLayoutInflater(); method public android.app.Dialog getWindow(); method public void hide(); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 0a53371..908d46e 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1189,12 +1189,12 @@ public class Am extends BaseCommand { private void runSetWatchHeap() throws Exception { String proc = nextArgRequired(); String limit = nextArgRequired(); - mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit)); + mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null); } private void runClearWatchHeap() throws Exception { String proc = nextArgRequired(); - mAm.setDumpHeapDebugLimit(proc, -1); + mAm.setDumpHeapDebugLimit(proc, 0, -1, null); } private void runBugReport() throws Exception { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d143f8b..8f125d7 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2682,6 +2682,47 @@ public class ActivityManager { } /** + * Request that the system start watching for the calling process to exceed a pss + * size as given here. Once called, the system will look for any occassions where it + * sees the associated process with a larger pss size and, when this happens, automatically + * pull a heap dump from it and allow the user to share the data. Note that this request + * continues running even if the process is killed and restarted. To remove the watch, + * use {@link #clearWatchHeapLimit()}. + * + * <p>This API only work if running on a debuggable (userdebug or eng) build.</p> + * + * <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly + * handle heap limit reports themselves.</p> + * + * @param pssSize The size in bytes to set the limit at. + */ + public void setWatchHeapLimit(long pssSize) { + try { + ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize, + mContext.getPackageName()); + } catch (RemoteException e) { + } + } + + /** + * Action an app can implement to handle reports from {@link #setWatchHeapLimit(long)}. + * If your package has an activity handling this action, it will be launched with the + * heap data provided to it the same way as {@link Intent#ACTION_SEND}. Note that to + * match the activty must support this action and a MIME type of "*/*". + */ + public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT"; + + /** + * Clear a heap watch limit previously set by {@link #setWatchHeapLimit(long)}. + */ + public void clearWatchHeapLimit() { + try { + ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null); + } catch (RemoteException e) { + } + } + + /** * @hide */ public void startLockTaskMode(int taskId) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1484af8..be7287f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2427,8 +2427,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String procName = data.readString(); + int uid = data.readInt(); long maxMemSize = data.readLong(); - setDumpHeapDebugLimit(procName, maxMemSize); + String reportPackage = data.readString(); + setDumpHeapDebugLimit(procName, uid, maxMemSize, reportPackage); reply.writeNoException(); return true; } @@ -5644,12 +5646,15 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException { + public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize, + String reportPackage) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(processName); + data.writeInt(uid); data.writeLong(maxMemSize); + data.writeString(reportPackage); mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 4bd2332..381c20c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -208,8 +208,12 @@ public class AppOpsManager { public static final int OP_ACTIVATE_VPN = 47; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ public static final int OP_WRITE_WALLPAPER = 48; + /** @hide Received the assist structure from an app. */ + public static final int OP_ASSIST_STRUCTURE = 49; + /** @hide Received a screenshot from assist. */ + public static final int OP_ASSIST_SCREENSHOT = 50; /** @hide */ - public static final int _NUM_OP = 49; + public static final int _NUM_OP = 51; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -288,6 +292,8 @@ public class AppOpsManager { OP_PROJECT_MEDIA, OP_ACTIVATE_VPN, OP_WRITE_WALLPAPER, + OP_ASSIST_STRUCTURE, + OP_ASSIST_SCREENSHOT, }; /** @@ -344,6 +350,8 @@ public class AppOpsManager { null, OPSTR_ACTIVATE_VPN, null, + null, + null, }; /** @@ -400,6 +408,8 @@ public class AppOpsManager { "PROJECT_MEDIA", "ACTIVATE_VPN", "WRITE_WALLPAPER", + "ASSIST_STRUCTURE", + "ASSIST_SCREENSHOT" }; /** @@ -456,6 +466,8 @@ public class AppOpsManager { null, // no permission for projecting media null, // no permission for activating vpn null, // no permission for supporting wallpaper + null, // no permission for receiving assist structure + null, // no permission for receiving assist screenshot }; /** @@ -513,6 +525,8 @@ public class AppOpsManager { null, //PROJECT_MEDIA UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER + null, // ASSIST_STRUCTURE + null, // ASSIST_SCREENSHOT }; /** @@ -569,6 +583,8 @@ public class AppOpsManager { false, //PROJECT_MEDIA false, //ACTIVATE_VPN false, //WALLPAPER + false, //ASSIST_STRUCTURE + false, //ASSIST_SCREENSHOT }; /** @@ -624,6 +640,8 @@ public class AppOpsManager { AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_ALLOWED, }; /** @@ -683,6 +701,8 @@ public class AppOpsManager { false, false, false, + false, + false, }; private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index d794aa3..e20b0da 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -482,7 +482,8 @@ public interface IActivityManager extends IInterface { public void systemBackupRestored() throws RemoteException; public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException; - public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException; + public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize, + String reportPackage) throws RemoteException; public void dumpHeapFinished(String path) throws RemoteException; public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake) diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index da7bb05..7acf5f0 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -103,9 +103,9 @@ public class VoiceInteractor { request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request - + " result=" + args.arg1); + + " result=" + args.arg2); if (request != null) { - ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg1); + ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg2); request.clear(); } break; @@ -297,6 +297,7 @@ public class VoiceInteractor { */ public static final class Option implements Parcelable { final CharSequence mLabel; + final int mIndex; ArrayList<CharSequence> mSynonyms; Bundle mExtras; @@ -308,6 +309,21 @@ public class VoiceInteractor { */ public Option(CharSequence label) { mLabel = label; + mIndex = -1; + } + + /** + * Creates an option that a user can select with their voice by matching the label + * or one of several synonyms. + * @param label The label that will both be matched against what the user speaks + * and displayed visually. + * @param index The location of this option within the overall set of options. + * Can be used to help identify which the option when it is returned from the + * voice interactor. + */ + public Option(CharSequence label, int index) { + mLabel = label; + mIndex = index; } /** @@ -328,6 +344,14 @@ public class VoiceInteractor { return mLabel; } + /** + * Return the index that was supplied in the constructor. + * If the option was constructed without an index, -1 is returned. + */ + public int getIndex() { + return mIndex; + } + public int countSynonyms() { return mSynonyms != null ? mSynonyms.size() : 0; } @@ -356,6 +380,7 @@ public class VoiceInteractor { Option(Parcel in) { mLabel = in.readCharSequence(); + mIndex = in.readInt(); mSynonyms = in.readCharSequenceList(); mExtras = in.readBundle(); } @@ -368,6 +393,7 @@ public class VoiceInteractor { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mLabel); + dest.writeInt(mIndex); dest.writeCharSequenceList(mSynonyms); dest.writeBundle(mExtras); } diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 4c31f80..20d7079 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -520,6 +520,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { mCallbacks, true); } + public Context getContext() { + return mContext; + } + Request newRequest(IVoiceInteractorCallback callback) { synchronized (this) { Request req = new Request(callback, this); @@ -832,6 +836,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { return false; } + /** + * Called when the user presses the back button while focus is in the session UI. Note + * that this will only happen if the session UI has requested input focus in its window; + * otherwise, the back key will go to whatever window has focus and do whatever behavior + * it normally has there. + */ public void onBackPressed() { hide(); } diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java index 7e70b0c..0ce501e 100644 --- a/core/java/com/android/internal/app/DumpHeapActivity.java +++ b/core/java/com/android/internal/app/DumpHeapActivity.java @@ -17,13 +17,16 @@ package com.android.internal.app; import android.app.Activity; +import android.app.ActivityManager; import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.DebugUtils; +import android.util.Slog; /** * This activity is displayed when the system has collected a heap dump from @@ -34,6 +37,8 @@ public class DumpHeapActivity extends Activity { public static final String KEY_PROCESS = "process"; /** The size limit the process reached */ public static final String KEY_SIZE = "size"; + /** Optional name of package to directly launch */ + public static final String KEY_DIRECT_LAUNCH = "direct_launch"; // Broadcast action to determine when to delete the current dump heap data. public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP"; @@ -54,6 +59,28 @@ public class DumpHeapActivity extends Activity { mProcess = getIntent().getStringExtra(KEY_PROCESS); mSize = getIntent().getLongExtra(KEY_SIZE, 0); + + String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH); + if (directLaunch != null) { + Intent intent = new Intent(ActivityManager.ACTION_REPORT_HEAP_LIMIT); + intent.setPackage(directLaunch); + ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI); + intent.setClipData(clip); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType(clip.getDescription().getMimeType(0)); + intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI); + try { + startActivity(intent); + scheduleDelete(); + mHandled = true; + finish(); + return; + } catch (ActivityNotFoundException e) { + Slog.i("DumpHeapActivity", "Unable to direct launch to " + directLaunch + + ": " + e.getMessage()); + } + } + AlertDialog.Builder b = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert); b.setTitle(com.android.internal.R.string.dump_heap_title); @@ -71,9 +98,7 @@ public class DumpHeapActivity extends Activity { @Override public void onClick(DialogInterface dialog, int which) { mHandled = true; - Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP); - broadcast.putExtra(EXTRA_DELAY_DELETE, true); - sendBroadcast(broadcast); + scheduleDelete(); Intent intent = new Intent(Intent.ACTION_SEND); ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI); intent.setClipData(clip); @@ -88,6 +113,12 @@ public class DumpHeapActivity extends Activity { mDialog = b.show(); } + void scheduleDelete() { + Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP); + broadcast.putExtra(EXTRA_DELAY_DELETE, true); + sendBroadcast(broadcast); + } + @Override protected void onStop() { super.onStop(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cf51004..c4c81be 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1124,7 +1124,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mAutoStopProfiler = false; int mProfileType = 0; String mOpenGlTraceApp = null; - final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>(); + final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>(); String mMemWatchDumpProcName; String mMemWatchDumpFile; int mMemWatchDumpPid; @@ -1830,11 +1830,21 @@ public final class ActivityManagerService extends ActivityManagerNative final String procName; final int uid; final long memLimit; + final String reportPackage; synchronized (ActivityManagerService.this) { procName = mMemWatchDumpProcName; uid = mMemWatchDumpUid; - Long limit = mMemWatchProcesses.get(procName); - memLimit = limit != null ? limit : 0; + Pair<Long, String> val = mMemWatchProcesses.get(procName, uid); + if (val == null) { + val = mMemWatchProcesses.get(procName, 0); + } + if (val != null) { + memLimit = val.first; + reportPackage = val.second; + } else { + memLimit = 0; + reportPackage = null; + } } if (procName == null) { return; @@ -1867,6 +1877,9 @@ public final class ActivityManagerService extends ActivityManagerNative intent.setClassName("android", DumpHeapActivity.class.getName()); intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName); intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit); + if (reportPackage != null) { + intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage); + } int userId = UserHandle.getUserId(uid); notification.setLatestEventInfo(mContext, text, mContext.getText(R.string.dump_heap_notification_detail), @@ -2474,11 +2487,19 @@ public final class ActivityManagerService extends ActivityManagerNative final void setFocusedActivityLocked(ActivityRecord r, String reason) { if (r != null && mFocusedActivity != r) { if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r); + ActivityRecord last = mFocusedActivity; mFocusedActivity = r; if (r.task != null && r.task.voiceInteractor != null) { startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid); } else { finishRunningVoiceLocked(); + if (last != null && last.task.voiceSession != null) { + // We had been in a voice interaction session, but now focused has + // move to something different. Just finish the session, we can't + // return to it and retain the proper state and synchronization with + // the voice interaction service. + finishVoiceTask(last.task.voiceSession); + } } if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) { mWindowManager.setFocusedApp(r.appToken, true); @@ -12855,16 +12876,28 @@ public final class ActivityManagerService extends ActivityManagerNative + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); } } - if (mMemWatchProcesses.size() > 0) { + if (mMemWatchProcesses.getMap().size() > 0) { pw.println(" Mem watch processes:"); - for (int i=0; i<mMemWatchProcesses.size(); i++) { - if (needSep) { - pw.println(); - needSep = false; + final ArrayMap<String, SparseArray<Pair<Long, String>>> procs + = mMemWatchProcesses.getMap(); + for (int i=0; i<procs.size(); i++) { + final String proc = procs.keyAt(i); + final SparseArray<Pair<Long, String>> uids = procs.valueAt(i); + for (int j=0; j<uids.size(); j++) { + if (needSep) { + pw.println(); + needSep = false; + } + StringBuilder sb = new StringBuilder(); + sb.append(" ").append(proc).append('/'); + UserHandle.formatUid(sb, uids.keyAt(j)); + Pair<Long, String> val = uids.valueAt(i); + sb.append(": "); DebugUtils.sizeValueToString(val.first, sb); + if (val.second != null) { + sb.append(", report to ").append(val.second); + } + pw.println(sb.toString()); } - pw.print(" "); pw.print(mMemWatchProcesses.keyAt(i)); - pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i)); - pw.println(); } pw.print(" mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName); pw.print(" mMemWatchDumpFile="); pw.println(mMemWatchDumpFile); @@ -17389,7 +17422,18 @@ public final class ActivityManagerService extends ActivityManagerNative proc.lastCachedPss = pss; } - Long check = mMemWatchProcesses.get(proc.processName); + final SparseArray<Pair<Long, String>> watchUids + = mMemWatchProcesses.getMap().get(proc.processName); + Long check = null; + if (watchUids != null) { + Pair<Long, String> val = watchUids.get(proc.uid); + if (val == null) { + val = watchUids.get(0); + } + if (val != null) { + check = val.first; + } + } if (check != null) { if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) { boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); @@ -17425,7 +17469,8 @@ public final class ActivityManagerService extends ActivityManagerNative IApplicationThread thread = myProc.thread; if (thread != null) { try { - if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting dump heap from " + if (true || DEBUG_PSS) Slog.d(TAG_PSS, + "Requesting dump heap from " + myProc + " to " + heapdumpFile); thread.dumpHeap(true, heapdumpFile.toString(), fd); } catch (RemoteException e) { @@ -18660,15 +18705,38 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void setDumpHeapDebugLimit(String processName, long maxMemSize) { - enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, - "setDumpHeapDebugLimit()"); + public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize, + String reportPackage) { + if (processName != null) { + enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, + "setDumpHeapDebugLimit()"); + } else { + if (!Build.IS_DEBUGGABLE) { + throw new SecurityException("Not running a debuggable build"); + } + synchronized (mPidsSelfLocked) { + ProcessRecord proc = mPidsSelfLocked.get(Binder.getCallingPid()); + if (proc == null) { + throw new SecurityException("No process found for calling pid " + + Binder.getCallingPid()); + } + processName = proc.processName; + uid = proc.uid; + if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) { + throw new SecurityException("Package " + reportPackage + " is not running in " + + proc); + } + } + } synchronized (this) { if (maxMemSize > 0) { - mMemWatchProcesses.put(processName, maxMemSize); - mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG); + mMemWatchProcesses.put(processName, uid, new Pair(maxMemSize, reportPackage)); } else { - mMemWatchProcesses.remove(processName); + if (uid != 0) { + mMemWatchProcesses.remove(processName, uid); + } else { + mMemWatchProcesses.getMap().remove(processName); + } } } } @@ -18686,7 +18754,7 @@ public final class ActivityManagerService extends ActivityManagerNative + " does not match last path " + mMemWatchDumpFile); return; } - if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path); + if (true || DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path); mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 1aa0d0b..bca757b 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -145,7 +145,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } public boolean hideSessionLocked(int callingPid, int callingUid) { - return mActiveSession.hideLocked(); + if (mActiveSession != null) { + return mActiveSession.hideLocked(); + } + return false; } public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, @@ -165,6 +168,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne Slog.w(TAG, "startVoiceActivity does not match active session"); return ActivityManager.START_CANCELED; } + if (!mActiveSession.mShown) { + Slog.w(TAG, "startVoiceActivity not allowed on hidden session"); + return ActivityManager.START_CANCELED; + } intent = new Intent(intent); intent.addCategory(Intent.CATEGORY_VOICE); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index 73c7363..607df2d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -18,6 +18,7 @@ package com.android.server.voiceinteraction; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.AppOpsManager; import android.app.AssistContent; import android.app.IActivityManager; import android.content.ClipData; @@ -62,6 +63,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { final int mCallingUid; final IActivityManager mAm; final IWindowManager mIWindowManager; + final AppOpsManager mAppOps; final IBinder mPermissionOwner; boolean mShown; Bundle mShowArgs; @@ -148,6 +150,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mAm = ActivityManagerNative.getDefault(); mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); + mAppOps = context.getSystemService(AppOpsManager.class); IBinder permOwner = null; try { permOwner = mAm.newUriPermissionOwner("voicesession:" @@ -159,7 +162,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); mBindIntent.setComponent(mSessionComponentName); mBound = mContext.bindServiceAsUser(mBindIntent, this, - Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser)); + Context.BIND_AUTO_CREATE|Context.BIND_WAIVE_PRIORITY + |Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser)); if (mBound) { try { mIWindowManager.addWindowToken(mToken, @@ -186,19 +190,31 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mShowFlags = flags; mHaveAssistData = false; if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) { - try { - mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, - mAssistReceiver); - } catch (RemoteException e) { + if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid, + mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) { + try { + mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, + mAssistReceiver); + } catch (RemoteException e) { + } + } else { + mHaveAssistData = true; + mAssistData = null; } } else { mAssistData = null; } mHaveScreenshot = false; if ((flags&VoiceInteractionService.START_WITH_SCREENSHOT) != 0) { - try { - mIWindowManager.requestAssistScreenshot(mScreenshotReceiver); - } catch (RemoteException e) { + if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid, + mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) { + try { + mIWindowManager.requestAssistScreenshot(mScreenshotReceiver); + } catch (RemoteException e) { + } + } else { + mHaveScreenshot = true; + mScreenshot = null; } } else { mScreenshot = null; @@ -335,6 +351,12 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mUser); } catch (RemoteException e) { } + if (mSession != null) { + try { + mAm.finishVoiceTask(mSession); + } catch (RemoteException e) { + } + } } if (mFullyBound) { mContext.unbindService(mFullConnection); diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml index 8c8151d..6209bd0 100644 --- a/tests/VoiceInteraction/res/layout/test_interaction.xml +++ b/tests/VoiceInteraction/res/layout/test_interaction.xml @@ -34,32 +34,49 @@ android:textAppearance="?android:attr/textAppearanceMedium" /> - <Button android:id="@+id/complete" - android:layout_width="wrap_content" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:text="@string/completeVoice" - /> + android:orientation="horizontal"> + + <Button android:id="@+id/complete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/completeVoice" + /> + + <Button android:id="@+id/abort" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/abortVoice" + /> + + <Button android:id="@+id/pick" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/pickVoice" + /> + + </LinearLayout> - <Button android:id="@+id/pick" - android:layout_width="wrap_content" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:text="@string/pickVoice" + android:layout_marginBottom="16dp" + android:orientation="horizontal"> + + <Button android:id="@+id/cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/cancelVoice" /> - <Button android:id="@+id/abort" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:text="@string/abortVoice" + <Button android:id="@+id/jump" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/jumpOut" /> - <Button android:id="@+id/cancel" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:text="@string/cancelVoice" - /> + </LinearLayout> </LinearLayout> diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml index 942c931..6289929 100644 --- a/tests/VoiceInteraction/res/values/strings.xml +++ b/tests/VoiceInteraction/res/values/strings.xml @@ -25,5 +25,6 @@ <string name="completeVoice">Complete Voice</string> <string name="pickVoice">Pick Voice</string> <string name="cancelVoice">Cancel</string> + <string name="jumpOut">Jump out</string> </resources> diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index ec727c4..3c5c201 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -16,6 +16,7 @@ package com.android.test.voiceinteraction; +import android.app.ActivityManager; import android.app.AssistContent; import android.app.AssistStructure; import android.app.VoiceInteractor; @@ -69,6 +70,8 @@ public class MainInteractionSession extends VoiceInteractionSession @Override public void onCreate(Bundle args, int startFlags) { super.onCreate(args); + ActivityManager am = getContext().getSystemService(ActivityManager.class); + am.setWatchHeapLimit(40*1024*1024); } @Override diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java index e195c30..9d24c59 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -19,6 +19,7 @@ package com.android.test.voiceinteraction; import android.app.Activity; import android.app.VoiceInteractor; import android.content.ComponentName; +import android.content.Intent; import android.os.Bundle; import android.service.voice.VoiceInteractionService; import android.util.Log; @@ -37,6 +38,7 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis Button mAbortButton; Button mCompleteButton; Button mPickButton; + Button mJumpOutButton; Button mCancelButton; @Override @@ -64,6 +66,8 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis mCompleteButton.setOnClickListener(this); mPickButton = (Button)findViewById(R.id.pick); mPickButton.setOnClickListener(this); + mJumpOutButton = (Button)findViewById(R.id.jump); + mJumpOutButton.setOnClickListener(this); mCancelButton = (Button)findViewById(R.id.cancel); mCancelButton.setOnClickListener(this); @@ -165,6 +169,13 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis } }; mInteractor.submitRequest(req); + } else if (v == mJumpOutButton) { + Log.i(TAG, "Jump out"); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setComponent(new ComponentName(this, VoiceInteractionMain.class)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); } else if (v == mCancelButton && mCurrentRequest != null) { Log.i(TAG, "Cancel request"); mCurrentRequest.cancel(); |