1 /* 2 * Copyright (C) 2006 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.server.am; 18 19 import com.android.internal.logging.MetricsLogger; 20 import com.android.internal.logging.nano.MetricsProto; 21 22 import android.content.ActivityNotFoundException; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.res.Resources; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.Message; 30 import android.text.BidiFormatter; 31 import android.util.Slog; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.view.WindowManager; 35 import android.widget.FrameLayout; 36 import android.widget.TextView; 37 38 final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnClickListener { 39 private static final String TAG = "AppNotRespondingDialog"; 40 41 // Event 'what' codes 42 static final int FORCE_CLOSE = 1; 43 static final int WAIT = 2; 44 static final int WAIT_AND_REPORT = 3; 45 46 public static final int CANT_SHOW = -1; 47 public static final int ALREADY_SHOWING = -2; 48 49 private final ActivityManagerService mService; 50 private final ProcessRecord mProc; 51 52 public AppNotRespondingDialog(ActivityManagerService service, Context context, 53 ProcessRecord app, ActivityRecord activity, boolean aboveSystem) { 54 super(context); 55 56 mService = service; 57 mProc = app; 58 Resources res = context.getResources(); 59 60 setCancelable(false); 61 62 int resid; 63 CharSequence name1 = activity != null 64 ? activity.info.loadLabel(context.getPackageManager()) 65 : null; 66 CharSequence name2 = null; 67 if ((app.pkgList.size() == 1) && 68 (name2=context.getPackageManager().getApplicationLabel(app.info)) != null) { 69 if (name1 != null) { 70 resid = com.android.internal.R.string.anr_activity_application; 71 } else { 72 name1 = name2; 73 name2 = app.processName; 74 resid = com.android.internal.R.string.anr_application_process; 75 } 76 } else { 77 if (name1 != null) { 78 name2 = app.processName; 79 resid = com.android.internal.R.string.anr_activity_process; 80 } else { 81 name1 = app.processName; 82 resid = com.android.internal.R.string.anr_process; 83 } 84 } 85 86 BidiFormatter bidi = BidiFormatter.getInstance(); 87 88 setTitle(name2 != null 89 ? res.getString(resid, bidi.unicodeWrap(name1.toString()), bidi.unicodeWrap(name2.toString())) 90 : res.getString(resid, bidi.unicodeWrap(name1.toString()))); 91 92 if (aboveSystem) { 93 getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); 94 } 95 WindowManager.LayoutParams attrs = getWindow().getAttributes(); 96 attrs.setTitle("Application Not Responding: " + app.info.processName); 97 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR | 98 WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 99 getWindow().setAttributes(attrs); 100 } 101 102 @Override 103 protected void onCreate(Bundle savedInstanceState) { 104 super.onCreate(savedInstanceState); 105 final FrameLayout frame = findViewById(android.R.id.custom); 106 final Context context = getContext(); 107 LayoutInflater.from(context).inflate( 108 com.android.internal.R.layout.app_anr_dialog, frame, true); 109 110 final TextView report = findViewById(com.android.internal.R.id.aerr_report); 111 report.setOnClickListener(this); 112 final boolean hasReceiver = mProc.errorReportReceiver != null; 113 report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE); 114 final TextView close = findViewById(com.android.internal.R.id.aerr_close); 115 close.setOnClickListener(this); 116 final TextView wait = findViewById(com.android.internal.R.id.aerr_wait); 117 wait.setOnClickListener(this); 118 119 findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE); 120 } 121 122 @Override 123 public void onClick(View v) { 124 switch (v.getId()) { 125 case com.android.internal.R.id.aerr_report: 126 mHandler.obtainMessage(WAIT_AND_REPORT).sendToTarget(); 127 break; 128 case com.android.internal.R.id.aerr_close: 129 mHandler.obtainMessage(FORCE_CLOSE).sendToTarget(); 130 break; 131 case com.android.internal.R.id.aerr_wait: 132 mHandler.obtainMessage(WAIT).sendToTarget(); 133 break; 134 default: 135 break; 136 } 137 } 138 139 private final Handler mHandler = new Handler() { 140 public void handleMessage(Message msg) { 141 Intent appErrorIntent = null; 142 143 MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_APP_ANR, 144 msg.what); 145 146 switch (msg.what) { 147 case FORCE_CLOSE: 148 // Kill the application. 149 mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this); 150 break; 151 case WAIT_AND_REPORT: 152 case WAIT: 153 // Continue waiting for the application. 154 synchronized (mService) { 155 ProcessRecord app = mProc; 156 157 if (msg.what == WAIT_AND_REPORT) { 158 appErrorIntent = mService.mAppErrors.createAppErrorIntentLocked(app, 159 System.currentTimeMillis(), null); 160 } 161 162 app.notResponding = false; 163 app.notRespondingReport = null; 164 if (app.anrDialog == AppNotRespondingDialog.this) { 165 app.anrDialog = null; 166 } 167 mService.mServices.scheduleServiceTimeoutLocked(app); 168 } 169 break; 170 } 171 172 if (appErrorIntent != null) { 173 try { 174 getContext().startActivity(appErrorIntent); 175 } catch (ActivityNotFoundException e) { 176 Slog.w(TAG, "bug report receiver dissappeared", e); 177 } 178 } 179 180 dismiss(); 181 } 182 }; 183 } 184