| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.shell; |
| |
| import static com.android.shell.HeapDumpProvider.makeUri; |
| import static com.android.shell.HeapDumpReceiver.ACTION_DELETE_HEAP_DUMP; |
| import static com.android.shell.HeapDumpReceiver.EXTRA_IS_USER_INITIATED; |
| import static com.android.shell.HeapDumpReceiver.EXTRA_PROCESS_NAME; |
| import static com.android.shell.HeapDumpReceiver.EXTRA_REPORT_PACKAGE; |
| import static com.android.shell.HeapDumpReceiver.EXTRA_SIZE_BYTES; |
| |
| import android.app.Activity; |
| import android.app.ActivityManager; |
| import android.app.AlertDialog; |
| import android.content.ActivityNotFoundException; |
| import android.content.ClipData; |
| import android.content.Intent; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Process; |
| import android.util.DebugUtils; |
| import android.util.Log; |
| |
| import com.android.internal.R; |
| |
| /** |
| * This activity is displayed when the system has collected a heap dump. |
| */ |
| public class HeapDumpActivity extends Activity { |
| private static final String TAG = "HeapDumpActivity"; |
| |
| static final String KEY_URI = "uri"; |
| |
| private AlertDialog mDialog; |
| private Uri mDumpUri; |
| private boolean mHandled = false; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| String process = getIntent().getStringExtra(EXTRA_PROCESS_NAME); |
| long size = getIntent().getLongExtra(EXTRA_SIZE_BYTES, 0); |
| final boolean isUserInitiated = getIntent().getBooleanExtra(EXTRA_IS_USER_INITIATED, false); |
| final int uid = getIntent().getIntExtra(Intent.EXTRA_UID, 0); |
| final boolean isSystemProcess = uid == Process.SYSTEM_UID; |
| mDumpUri = makeUri(process); |
| final String procDisplayName = isSystemProcess |
| ? getString(com.android.internal.R.string.android_system_label) |
| : process; |
| |
| final Intent sendIntent = new Intent(); |
| ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", mDumpUri); |
| sendIntent.setClipData(clip); |
| sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); |
| sendIntent.setType(clip.getDescription().getMimeType(0)); |
| sendIntent.putExtra(Intent.EXTRA_STREAM, mDumpUri); |
| |
| String directLaunchPackage = getIntent().getStringExtra(EXTRA_REPORT_PACKAGE); |
| if (directLaunchPackage != null) { |
| sendIntent.setAction(ActivityManager.ACTION_REPORT_HEAP_LIMIT); |
| sendIntent.setPackage(directLaunchPackage); |
| try { |
| startActivity(sendIntent); |
| mHandled = true; |
| finish(); |
| return; |
| } catch (ActivityNotFoundException e) { |
| Log.e(TAG, "Unable to direct launch to " + directLaunchPackage, e); |
| } |
| } |
| |
| final int messageId; |
| if (isUserInitiated) { |
| messageId = com.android.internal.R.string.dump_heap_ready_text; |
| } else if (isSystemProcess) { |
| messageId = com.android.internal.R.string.dump_heap_system_text; |
| } else { |
| messageId = com.android.internal.R.string.dump_heap_text; |
| } |
| mDialog = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert) |
| .setTitle(com.android.internal.R.string.dump_heap_title) |
| .setMessage(getString(messageId, procDisplayName, |
| DebugUtils.sizeValueToString(size, null))) |
| .setNegativeButton(android.R.string.cancel, (dialog, which) -> { |
| mHandled = true; |
| finish(); |
| }) |
| .setNeutralButton(R.string.delete, (dialog, which) -> { |
| mHandled = true; |
| Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP); |
| deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class); |
| deleteIntent.putExtra(KEY_URI, mDumpUri.toString()); |
| sendBroadcast(deleteIntent); |
| finish(); |
| }) |
| .setPositiveButton(android.R.string.ok, (dialog, which) -> { |
| mHandled = true; |
| sendIntent.setAction(Intent.ACTION_SEND); |
| sendIntent.setPackage(null); |
| startActivity(Intent.createChooser(sendIntent, |
| getText(com.android.internal.R.string.dump_heap_title))); |
| finish(); |
| }) |
| .show(); |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| if (!isChangingConfigurations()) { |
| if (!mHandled) { |
| Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP); |
| deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class); |
| deleteIntent.putExtra(KEY_URI, mDumpUri.toString()); |
| sendBroadcast(deleteIntent); |
| } |
| } |
| } |
| |
| @Override |
| protected void onDestroy() { |
| super.onDestroy(); |
| if (mDialog != null) { |
| mDialog.dismiss(); |
| } |
| } |
| } |