Home | History | Annotate | Download | only in am
      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