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