• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.app.ActivityTaskManager.INVALID_TASK_ID;
20 
21 import android.content.Context;
22 import android.content.res.Resources;
23 import android.os.Build;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.provider.Settings;
28 import android.text.BidiFormatter;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.WindowManager;
32 import android.widget.FrameLayout;
33 import android.widget.TextView;
34 
35 final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListener {
36 
37     private final ActivityManagerService mService;
38     private final ActivityManagerGlobalLock mProcLock;
39     private final AppErrorResult mResult;
40     private final ProcessRecord mProc;
41     private final boolean mIsRestartable;
42 
43     static int CANT_SHOW = -1;
44     static int BACKGROUND_USER = -2;
45     static int ALREADY_SHOWING = -3;
46 
47     // Event 'what' codes
48     static final int FORCE_QUIT = 1;
49     static final int FORCE_QUIT_AND_REPORT = 2;
50     static final int RESTART = 3;
51     static final int MUTE = 5;
52     static final int TIMEOUT = 6;
53     static final int CANCEL = 7;
54     static final int APP_INFO = 8;
55 
56     // 5-minute timeout, then we automatically dismiss the crash dialog
57     static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
58 
AppErrorDialog(Context context, ActivityManagerService service, Data data)59     public AppErrorDialog(Context context, ActivityManagerService service, Data data) {
60         super(context);
61         Resources res = context.getResources();
62 
63         mService = service;
64         mProcLock = service.mProcLock;
65         mProc = data.proc;
66         mResult = data.result;
67         mIsRestartable = (data.taskId != INVALID_TASK_ID || data.isRestartableForService)
68                 && Settings.Global.getInt(context.getContentResolver(),
69                 Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, 0) != 0;
70         BidiFormatter bidi = BidiFormatter.getInstance();
71 
72         CharSequence name;
73         if (mProc.getPkgList().size() == 1
74                 && (name = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
75             setTitle(res.getString(
76                     data.repeating ? com.android.internal.R.string.aerr_application_repeated
77                             : com.android.internal.R.string.aerr_application,
78                     bidi.unicodeWrap(name.toString()),
79                     bidi.unicodeWrap(mProc.info.processName)));
80         } else {
81             name = mProc.processName;
82             setTitle(res.getString(
83                     data.repeating ? com.android.internal.R.string.aerr_process_repeated
84                             : com.android.internal.R.string.aerr_process,
85                     bidi.unicodeWrap(name.toString())));
86         }
87 
88         setCancelable(true);
89         setCancelMessage(mHandler.obtainMessage(CANCEL));
90 
91         WindowManager.LayoutParams attrs = getWindow().getAttributes();
92         attrs.setTitle("Application Error: " + mProc.info.processName);
93         attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
94                 | WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
95         getWindow().setAttributes(attrs);
96         if (mProc.isPersistent()) {
97             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
98         }
99 
100         // After the timeout, pretend the user clicked the quit button
101         mHandler.sendMessageDelayed(
102                 mHandler.obtainMessage(TIMEOUT),
103                 DISMISS_TIMEOUT);
104     }
105 
106     @Override
onCreate(Bundle savedInstanceState)107     protected void onCreate(Bundle savedInstanceState) {
108         super.onCreate(savedInstanceState);
109         final FrameLayout frame = findViewById(android.R.id.custom);
110         final Context context = getContext();
111         LayoutInflater.from(context).inflate(
112                 com.android.internal.R.layout.app_error_dialog, frame, true);
113 
114         final boolean hasReceiver = mProc.mErrorState.getErrorReportReceiver() != null;
115 
116         final TextView restart = findViewById(com.android.internal.R.id.aerr_restart);
117         restart.setOnClickListener(this);
118         restart.setVisibility(mIsRestartable ? View.VISIBLE : View.GONE);
119         final TextView report = findViewById(com.android.internal.R.id.aerr_report);
120         report.setOnClickListener(this);
121         report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE);
122         final TextView close = findViewById(com.android.internal.R.id.aerr_close);
123         close.setOnClickListener(this);
124         final TextView appInfo = findViewById(com.android.internal.R.id.aerr_app_info);
125         appInfo.setOnClickListener(this);
126 
127         boolean showMute = !Build.IS_USER && Settings.Global.getInt(context.getContentResolver(),
128                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0
129                 && Settings.Global.getInt(context.getContentResolver(),
130                 Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG, 0) != 0;
131         final TextView mute = findViewById(com.android.internal.R.id.aerr_mute);
132         mute.setOnClickListener(this);
133         mute.setVisibility(showMute ? View.VISIBLE : View.GONE);
134 
135         findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
136     }
137 
138     private final Handler mHandler = new Handler() {
139         public void handleMessage(Message msg) {
140             setResult(msg.what);
141             dismiss();
142         }
143     };
144 
145     @Override
dismiss()146     public void dismiss() {
147         if (!mResult.mHasResult) {
148             // We are dismissing and the result has not been set...go ahead and set.
149             setResult(FORCE_QUIT);
150         }
151         super.dismiss();
152     }
153 
setResult(int result)154     private void setResult(int result) {
155         synchronized (mProcLock) {
156             if (mProc != null) {
157                 // Don't dismiss again since it leads to recursive call between dismiss and this
158                 // method.
159                 mProc.mErrorState.getDialogController().clearCrashDialogs(false /* needDismiss */);
160             }
161         }
162         mResult.set(result);
163 
164         // Make sure we don't have time timeout still hanging around.
165         mHandler.removeMessages(TIMEOUT);
166     }
167 
168     @Override
onClick(View v)169     public void onClick(View v) {
170         switch (v.getId()) {
171             case com.android.internal.R.id.aerr_restart:
172                 mHandler.obtainMessage(RESTART).sendToTarget();
173                 break;
174             case com.android.internal.R.id.aerr_report:
175                 mHandler.obtainMessage(FORCE_QUIT_AND_REPORT).sendToTarget();
176                 break;
177             case com.android.internal.R.id.aerr_close:
178                 mHandler.obtainMessage(FORCE_QUIT).sendToTarget();
179                 break;
180             case com.android.internal.R.id.aerr_app_info:
181                 mHandler.obtainMessage(APP_INFO).sendToTarget();
182                 break;
183             case com.android.internal.R.id.aerr_mute:
184                 mHandler.obtainMessage(MUTE).sendToTarget();
185                 break;
186             default:
187                 break;
188         }
189     }
190 
191     static class Data {
192         AppErrorResult result;
193         int taskId;
194         boolean repeating;
195         ProcessRecord proc;
196         boolean isRestartableForService;
197     }
198 }
199