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