• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.shell;
18 
19 import static com.android.shell.HeapDumpProvider.makeUri;
20 import static com.android.shell.HeapDumpReceiver.ACTION_DELETE_HEAP_DUMP;
21 import static com.android.shell.HeapDumpReceiver.EXTRA_IS_USER_INITIATED;
22 import static com.android.shell.HeapDumpReceiver.EXTRA_PROCESS_NAME;
23 import static com.android.shell.HeapDumpReceiver.EXTRA_REPORT_PACKAGE;
24 import static com.android.shell.HeapDumpReceiver.EXTRA_SIZE_BYTES;
25 
26 import android.app.Activity;
27 import android.app.ActivityManager;
28 import android.app.AlertDialog;
29 import android.content.ActivityNotFoundException;
30 import android.content.ClipData;
31 import android.content.Intent;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.os.Process;
35 import android.util.DebugUtils;
36 import android.util.Log;
37 
38 import com.android.internal.R;
39 
40 /**
41  * This activity is displayed when the system has collected a heap dump.
42  */
43 public class HeapDumpActivity extends Activity {
44     private static final String TAG = "HeapDumpActivity";
45 
46     static final String KEY_URI = "uri";
47 
48     private AlertDialog mDialog;
49     private Uri mDumpUri;
50     private boolean mHandled = false;
51 
52     @Override
onCreate(Bundle savedInstanceState)53     protected void onCreate(Bundle savedInstanceState) {
54         super.onCreate(savedInstanceState);
55 
56         String process = getIntent().getStringExtra(EXTRA_PROCESS_NAME);
57         long size = getIntent().getLongExtra(EXTRA_SIZE_BYTES, 0);
58         final boolean isUserInitiated = getIntent().getBooleanExtra(EXTRA_IS_USER_INITIATED, false);
59         final int uid = getIntent().getIntExtra(Intent.EXTRA_UID, 0);
60         final boolean isSystemProcess = uid == Process.SYSTEM_UID;
61         mDumpUri = makeUri(process);
62         final String procDisplayName = isSystemProcess
63                 ? getString(com.android.internal.R.string.android_system_label)
64                 : process;
65 
66         final Intent sendIntent = new Intent();
67         ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", mDumpUri);
68         sendIntent.setClipData(clip);
69         sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
70         sendIntent.setType(clip.getDescription().getMimeType(0));
71         sendIntent.putExtra(Intent.EXTRA_STREAM, mDumpUri);
72 
73         String directLaunchPackage = getIntent().getStringExtra(EXTRA_REPORT_PACKAGE);
74         if (directLaunchPackage != null) {
75             sendIntent.setAction(ActivityManager.ACTION_REPORT_HEAP_LIMIT);
76             sendIntent.setPackage(directLaunchPackage);
77             try {
78                 startActivity(sendIntent);
79                 mHandled = true;
80                 finish();
81                 return;
82             } catch (ActivityNotFoundException e) {
83                 Log.e(TAG, "Unable to direct launch to " + directLaunchPackage, e);
84             }
85         }
86 
87         final int messageId;
88         if (isUserInitiated) {
89             messageId = com.android.internal.R.string.dump_heap_ready_text;
90         } else if (isSystemProcess) {
91             messageId = com.android.internal.R.string.dump_heap_system_text;
92         } else {
93             messageId = com.android.internal.R.string.dump_heap_text;
94         }
95         mDialog = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert)
96                 .setTitle(com.android.internal.R.string.dump_heap_title)
97                 .setMessage(getString(messageId, procDisplayName,
98                         DebugUtils.sizeValueToString(size, null)))
99                 .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
100                     mHandled = true;
101                     finish();
102                 })
103                 .setNeutralButton(R.string.delete, (dialog, which) -> {
104                     mHandled = true;
105                     Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP);
106                     deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class);
107                     deleteIntent.putExtra(KEY_URI, mDumpUri.toString());
108                     sendBroadcast(deleteIntent);
109                     finish();
110                 })
111                 .setPositiveButton(android.R.string.ok, (dialog, which) -> {
112                     mHandled = true;
113                     sendIntent.setAction(Intent.ACTION_SEND);
114                     sendIntent.setPackage(null);
115                     startActivity(Intent.createChooser(sendIntent,
116                             getText(com.android.internal.R.string.dump_heap_title)));
117                     finish();
118                 })
119                 .show();
120     }
121 
122     @Override
onStop()123     protected void onStop() {
124         super.onStop();
125         if (!isChangingConfigurations()) {
126             if (!mHandled) {
127                 Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP);
128                 deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class);
129                 deleteIntent.putExtra(KEY_URI, mDumpUri.toString());
130                 sendBroadcast(deleteIntent);
131             }
132         }
133     }
134 
135     @Override
onDestroy()136     protected void onDestroy() {
137         super.onDestroy();
138         if (mDialog != null) {
139             mDialog.dismiss();
140         }
141     }
142 }
143