1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.app; 18 19 import android.app.Activity; 20 import android.app.ActivityManager; 21 import android.app.AlertDialog; 22 import android.content.ActivityNotFoundException; 23 import android.content.ClipData; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.util.DebugUtils; 29 import android.util.Slog; 30 31 /** 32 * This activity is displayed when the system has collected a heap dump from 33 * a large process and the user has selected to share it. 34 */ 35 public class DumpHeapActivity extends Activity { 36 /** The process we are reporting */ 37 public static final String KEY_PROCESS = "process"; 38 /** The size limit the process reached */ 39 public static final String KEY_SIZE = "size"; 40 /** Optional name of package to directly launch */ 41 public static final String KEY_DIRECT_LAUNCH = "direct_launch"; 42 43 // Broadcast action to determine when to delete the current dump heap data. 44 public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP"; 45 46 // Extra for above: delay delete of data, since the user is in the process of sharing it. 47 public static final String EXTRA_DELAY_DELETE = "delay_delete"; 48 49 static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java"); 50 51 String mProcess; 52 long mSize; 53 AlertDialog mDialog; 54 boolean mHandled = false; 55 56 @Override onCreate(Bundle savedInstanceState)57 protected void onCreate(Bundle savedInstanceState) { 58 super.onCreate(savedInstanceState); 59 60 mProcess = getIntent().getStringExtra(KEY_PROCESS); 61 mSize = getIntent().getLongExtra(KEY_SIZE, 0); 62 63 String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH); 64 if (directLaunch != null) { 65 Intent intent = new Intent(ActivityManager.ACTION_REPORT_HEAP_LIMIT); 66 intent.setPackage(directLaunch); 67 ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI); 68 intent.setClipData(clip); 69 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 70 intent.setType(clip.getDescription().getMimeType(0)); 71 intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI); 72 try { 73 startActivity(intent); 74 scheduleDelete(); 75 mHandled = true; 76 finish(); 77 return; 78 } catch (ActivityNotFoundException e) { 79 Slog.i("DumpHeapActivity", "Unable to direct launch to " + directLaunch 80 + ": " + e.getMessage()); 81 } 82 } 83 84 AlertDialog.Builder b = new AlertDialog.Builder(this, 85 android.R.style.Theme_Material_Light_Dialog_Alert); 86 b.setTitle(com.android.internal.R.string.dump_heap_title); 87 b.setMessage(getString(com.android.internal.R.string.dump_heap_text, 88 mProcess, DebugUtils.sizeValueToString(mSize, null))); 89 b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 90 @Override 91 public void onClick(DialogInterface dialog, int which) { 92 mHandled = true; 93 sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP)); 94 finish(); 95 } 96 }); 97 b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 98 @Override 99 public void onClick(DialogInterface dialog, int which) { 100 mHandled = true; 101 scheduleDelete(); 102 Intent intent = new Intent(Intent.ACTION_SEND); 103 ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI); 104 intent.setClipData(clip); 105 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 106 intent.setType(clip.getDescription().getMimeType(0)); 107 intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI); 108 startActivity(Intent.createChooser(intent, 109 getText(com.android.internal.R.string.dump_heap_title))); 110 finish(); 111 } 112 }); 113 mDialog = b.show(); 114 } 115 scheduleDelete()116 void scheduleDelete() { 117 Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP); 118 broadcast.putExtra(EXTRA_DELAY_DELETE, true); 119 sendBroadcast(broadcast); 120 } 121 122 @Override onStop()123 protected void onStop() { 124 super.onStop(); 125 if (!isChangingConfigurations()) { 126 if (!mHandled) { 127 sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP)); 128 } 129 } 130 } 131 132 @Override onDestroy()133 protected void onDestroy() { 134 super.onDestroy(); 135 mDialog.dismiss(); 136 } 137 } 138