/** * Creates a command set for commands operation. * * @param pid process id * @param uid user id * @param setName command set name * @param featureType feature type * @return result */ public int createSetLocked(int pid, int uid, String setName, int featureType) { // TODO Auto-generated method stub int result = VoiceCommonState.SUCCESS; ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (listenerRecord == null) { // Check whether is illegal process from third party application // Maybe third application connect service without using // VoiceCommandManager result = VoiceCommonState.PROCESS_ILLEGAL; } else { if (setName.equals(listenerRecord.getSetName())) { // The setName already in used ,so don't need to ask swip // creating the set result = VoiceCommonState.SET_ALREADY_EXIST; } else { // Ask Swip whether the setName is created String swipSet = ProcessRecord.getSetNameForSwip( processRecord.getProcssName(), processRecord.getPid(), getFeatureName(featureType), setName); result = mSwip.createSetName(swipSet, featureType); } } return result; }
/** * Checks if the command set already exists. * * @param pid process id * @param uid user id * @param setName command set name * @param featureType feature type * @return result */ public int isSetCreatedLocked(int pid, int uid, String setName, int featureType) { int result = VoiceCommonState.SUCCESS; ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (processRecord == null || listenerRecord == null) { // Check whether is illegal process from third party application // Maybe third application connect service without using // VoiceCommandManager result = VoiceCommonState.PROCESS_ILLEGAL; } else { // Ask swip to check whether the set is already created if (!setName.equals(listenerRecord.getSetName())) { // First check whether the set is already selected String swipSet = ProcessRecord.getSetNameForSwip( processRecord.getProcssName(), processRecord.getPid(), getFeatureName(featureType), setName); result = mSwip.isSetCreated(swipSet, featureType); } } return result; }
/** * Remove process record for voice extension service. * * @param pid process id * @param uid user id */ public void removeProcessRecordLocked(int pid, int uid) { ProcessRecord record = mProcessRecords.get(pid); if (record != null && record.getUid() == uid) { mProcessRecords.remove(pid); } }
/** * @param conf used to contact HBase and to run jobs against * @param cluster for which to process records. * @param processFileSubstring return rows where the process file path contains this string. If * <code>null</code> or empty string, then no filtering is applied. * @return whether all job files for all processRecords were properly Printed. * @throws IOException */ private boolean printProcessRecordsFromHBase( Configuration conf, String cluster, int maxCount, String processFileSubstring) throws IOException { ProcessRecordService processRecordService = new ProcessRecordService(conf); List<ProcessRecord> processRecords = processRecordService.getProcessRecords(cluster, maxCount, processFileSubstring); try { int jobFileCount = 0; System.out.println("ProcessRecords for " + cluster + ": " + processRecords.size()); // Iterate over 0 based list in reverse order for (int j = processRecords.size() - 1; j >= 0; j--) { ProcessRecord processRecord = processRecords.get(j); // Print the whole thing. System.out.println(processRecord); jobFileCount += processRecord.getProcessedJobFiles(); } System.out.println( "Printed " + processRecords.size() + " records with a total of " + jobFileCount + " files."); } finally { processRecordService.close(); } return true; }
/** * The callback result of process dead. * * @param record process record */ public void onProcessDiedLocked(ProcessRecord record) { if (mSwipOccupiedProcess == record) { mSwipOccupiedProcess = null; } removeProcessRecordLocked(record.getPid(), record.getUid()); }
/** * Get the process record with the same pid & uid. * * @param pid process id * @param uid user id * @return process record */ public ProcessRecord getProcessRecordLocked(int pid, int uid) { ProcessRecord record = mProcessRecords.get(pid); if (record != null && record.getUid() != uid) { record = null; // mProcessRecords.remove(pid); } return record; }
/** * Gets all command sets. * * @param pid process id * @param uid user id * @param featureType feature type * @return all command sets */ public String[] getAllSetsLocked(int pid, int uid, int featureType) { String[] sets = null; ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (listenerRecord != null) { // Ask swip to get the sets of this process sets = mSwip.getAllSets(processRecord.getProcssName(), featureType); } return sets; }
void handleShowAnrUi(Message msg) { Dialog d = null; synchronized (mService) { HashMap<String, Object> data = (HashMap<String, Object>) msg.obj; ProcessRecord proc = (ProcessRecord) data.get("app"); if (proc != null && proc.anrDialog != null) { Slog.e(TAG, "App already has anr dialog: " + proc); MetricsLogger.action( mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.ALREADY_SHOWING); return; } Intent intent = new Intent("android.intent.action.ANR"); if (!mService.mProcessesReady) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); } mService.broadcastIntentLocked( null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); if (mService.canShowErrorDialogs()) { d = new AppNotRespondingDialog( mService, mContext, proc, (ActivityRecord) data.get("activity"), msg.arg1 != 0); proc.anrDialog = d; } else { MetricsLogger.action( mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.CANT_SHOW); // Just kill the app if there is no dialog to be shown. mService.killAppAtUsersRequest(proc, null); } } // If we've created a crash dialog, show it without the lock held if (d != null) { d.show(); } }
private void makeAppNotRespondingLocked( ProcessRecord app, String activity, String shortMsg, String longMsg) { app.notResponding = true; app.notRespondingReport = generateProcessError( app, ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, activity, shortMsg, longMsg, null); startAppProblemLocked(app); app.stopFreezingAllLocked(); }
void startAppProblemLocked(ProcessRecord app) { // If this app is not running under the current user, then we // can't give it a report button because that would require // launching the report UI under a different user. app.errorReportReceiver = null; for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) { if (app.userId == userId) { app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( mContext, app.info.packageName, app.info.flags); } } mService.skipCurrentReceiverLocked(app); }
/** * Gets the current selected command set. * * @param pid process id * @param uid user id * @param featureType feature type * @return the current selected command set */ public String getSetSelected(int pid, int uid, int featureType) { String setName = null; ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (listenerRecord != null) { // Check whether is illegal process from third party application // Maybe third application connect service without using // VoiceCommandManager setName = listenerRecord.getSetName(); } return setName; }
void handleShowAppErrorUi(Message msg) { AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj; boolean showBackground = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; synchronized (mService) { ProcessRecord proc = data.proc; AppErrorResult res = data.result; if (proc != null && proc.crashDialog != null) { Slog.e(TAG, "App already has crash dialog: " + proc); if (res != null) { res.set(AppErrorDialog.ALREADY_SHOWING); } return; } boolean isBackground = (UserHandle.getAppId(proc.uid) >= Process.FIRST_APPLICATION_UID && proc.pid != MY_PID); for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) { isBackground &= (proc.userId != userId); } if (isBackground && !showBackground) { Slog.w(TAG, "Skipping crash dialog of " + proc + ": background"); if (res != null) { res.set(AppErrorDialog.BACKGROUND_USER); } return; } final boolean crashSilenced = mAppsNotReportingCrashes != null && mAppsNotReportingCrashes.contains(proc.info.packageName); if (mService.canShowErrorDialogs() && !crashSilenced) { proc.crashDialog = new AppErrorDialog(mContext, mService, data); } else { // The device is asleep, so just pretend that the user // saw a crash dialog and hit "force quit". if (res != null) { res.set(AppErrorDialog.CANT_SHOW); } } } // If we've created a crash dialog, show it without the lock held if (data.proc.crashDialog != null) { data.proc.crashDialog.show(); } }
/** * Get the process record with the same processName. * * @param processName process name * @return process record */ public ProcessRecord getProcessRecordLocked(String processName) { ProcessRecord record = null; if (mSwipOccupiedProcess != null && mSwipOccupiedProcess.getProcssName().equals(processName)) { record = mSwipOccupiedProcess; } else { Iterator<Entry<Integer, ProcessRecord>> iterator = mProcessRecords.entrySet().iterator(); while (iterator.hasNext()) { record = iterator.next().getValue(); if (!record.getProcssName().equals(processName)) { record = null; continue; } break; } } return record; }
private boolean makeAppCrashingLocked( ProcessRecord app, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { app.crashing = true; app.crashingReport = generateProcessError( app, ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); startAppProblemLocked(app); app.stopFreezingAllLocked(); return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace, data); }
private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { throw new RemoteException(); } r.receiver = app.thread.asBinder(); r.curApp = app; app.curReceiver = r; mService.updateLruProcessLocked(app, true); // Tell the application to launch this receiver. r.intent.setComponent(r.curComponent); boolean started = false; try { if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Delivering to component " + r.curComponent + ": " + r); mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver( new Intent(r.intent), r.curReceiver, mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId); if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; } finally { if (!started) { if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; app.curReceiver = null; } } }
/** * Switch occupied swip process record. * * @param processRecord process record * @param featureType feature type * @return result */ public int switchSwipOccupiedProcessLocked(ProcessRecord processRecord, int featureType) { int result = VoiceCommonState.SUCCESS; ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (processRecord == null || listenerRecord == null) { result = VoiceCommonState.PROCESS_ILLEGAL; } else { if (mSwipOccupiedProcess != null && processRecord != mSwipOccupiedProcess) { result = VoiceCommonState.MIC_OCCUPIED; } else { // (1)Switch process record mSwipOccupiedProcess = processRecord; // Means switch success , current mSwipOccupiedProcess can // access swip // (2)Switch listener record result = processRecord.switchSwipListenerRecord(listenerRecord); } } return result; }
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, String message) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid // still has any relation to current pids, so must scan through the // list. synchronized (mService.mPidsSelfLocked) { for (int i = 0; i < mService.mPidsSelfLocked.size(); i++) { ProcessRecord p = mService.mPidsSelfLocked.valueAt(i); if (p.uid != uid) { continue; } if (p.pid == initialPid) { proc = p; break; } if (p.pkgList.containsKey(packageName)) { proc = p; } } } if (proc == null) { Slog.w( TAG, "crashApplication: nothing for uid=" + uid + " initialPid=" + initialPid + " packageName=" + packageName); return; } proc.scheduleCrash(message); }
/** * Register record for application from voice service. * * @param pid process id * @param uid user id * @param listener a callback that receive asynchronous notification from swip * @param featureType feature type * @param commonState common state or main state * @param featureState feture state or sub state * @param handler FeatureManager instance * @return result */ public int registerListenerLocked( int pid, int uid, Object listener, int featureType, int commonState, int featureState, FeatureManager handler) { int result = VoiceCommonState.SUCCESS; ProcessRecord processRecord = createProcessRecordLocked(pid, uid); String featureName = getFeatureName(featureType); if (processRecord == null) { result = VoiceCommonState.PROCESS_ILLEGAL; } else { ListenerRecord record = processRecord.getListenerRecord(featureName); if (record == null) { record = processRecord.createListenerRecord(); try { ((IInterface) listener).asBinder().linkToDeath(processRecord, 0); processRecord.addListenerRecord(featureName, record); } catch (RemoteException ex) { result = VoiceCommonState.PROCESS_ILLEGAL; } } else { // This case only can be happened while service didn't // receive // the died notification. // We need to notify native if possible if (CommonManager.DEBUG) { Log.d( TAG, "Register listener old pid=" + processRecord.getPid() + " old uid=" + processRecord.getUid() + " old processName=" + processRecord.getProcssName()); } } if (result == VoiceCommonState.SUCCESS) { record.init(listener, featureType, featureName, commonState, featureState, handler); } } return result; }
private boolean handleAppCrashInActivityController( ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo, String shortMsg, String longMsg, String stackTrace, long timeMillis) { if (mService.mController == null) { return false; } try { String name = r != null ? r.processName : null; int pid = r != null ? r.pid : Binder.getCallingPid(); int uid = r != null ? r.info.uid : Binder.getCallingUid(); if (!mService.mController.appCrashed( name, pid, shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")) && "Native crash".equals(crashInfo.exceptionClassName)) { Slog.w(TAG, "Skip killing native crashed app " + name + "(" + pid + ") during testing"); } else { Slog.w(TAG, "Force-killing crashed app " + name + " at watcher's request"); if (r != null) { if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)) { r.kill("crash", true); } } else { // Huh. Process.killProcess(pid); ActivityManagerService.killProcessGroup(uid, pid); } } return true; } } catch (RemoteException e) { mService.mController = null; Watchdog.getInstance().setActivityController(null); } return false; }
/** * Selects a command set for setting up commands or command recognition operation. * * @param pid process id * @param uid user id * @param setName command set name * @param featureType feature type * @return result */ public int selectSetLocked(int pid, int uid, String setName, int featureType) { int result = VoiceCommonState.SUCCESS; if (setName == null) { result = VoiceCommonState.SET_ILLEGAL; Log.e(TAG, "select Set fail, set name =" + setName); } else { ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (processRecord == null || listenerRecord == null) { // Check whether is illegal process from third party application // Maybe third application connect service without using // VoiceCommandManager result = VoiceCommonState.PROCESS_ILLEGAL; } else if (setName.equals(listenerRecord.getSetName())) { result = VoiceCommonState.SET_SELECTED; } else if (processRecord.isListenerOccupiedSwip(listenerRecord)) { // Current listenerRecord occupy the swip , can't switch set result = VoiceCommonState.MIC_OCCUPIED; } else { // Ask swip that is this set created String swipSet = ProcessRecord.getSetNameForSwip( processRecord.getProcssName(), processRecord.getPid(), getFeatureName(featureType), setName); result = mSwip.isSetCreated(swipSet, featureType); if (result == VoiceCommonState.SET_ALREADY_EXIST) { listenerRecord.setSetName(setName); // result = processRecord // .switchSwipListenerRecord(listenerRecord); result = VoiceCommonState.SUCCESS; } } } return result; }
void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { app.crashing = false; app.crashingReport = null; app.notResponding = false; app.notRespondingReport = null; if (app.anrDialog == fromDialog) { app.anrDialog = null; } if (app.waitDialog == fromDialog) { app.waitDialog = null; } if (app.pid > 0 && app.pid != MY_PID) { handleAppCrashLocked( app, "user-terminated" /*reason*/, null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); app.kill("user request after error", true); } }
/** * Deletes the command set. * * @param pid process id * @param uid user id * @param setName command set name * @param featureType feature type * @return result */ public int deleteSetLocked(int pid, int uid, String setName, int featureType) { int result = VoiceCommonState.SUCCESS; ProcessRecord processRecord = getProcessRecordLocked(pid, uid); ListenerRecord listenerRecord = processRecord == null ? null : processRecord.getListenerRecord(getFeatureName(featureType)); if (processRecord == null || listenerRecord == null) { // Check whether is illegal process from third party application // Maybe third application connect service without using // VoiceCommandManager result = VoiceCommonState.PROCESS_ILLEGAL; } else { if (setName.equals(listenerRecord.getSetName())) { if (listenerRecord == processRecord.getSwipListenerRecord()) { // The setName already in used ,so we need to check state // Swip is using the set , so we can't delete the set result = VoiceCommonState.SET_OCCUPIED; } else { listenerRecord.setSetName(null); } } // Ask swip to delete the set // listenerRecord.selectSet(null); if (result == VoiceCommonState.SUCCESS) { String swipSet = ProcessRecord.getSetNameForSwip( processRecord.getProcssName(), processRecord.getPid(), getFeatureName(featureType), setName); result = mSwip.deleteSetName(swipSet); } } return result; }
boolean handleAppCrashLocked( ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { long now = SystemClock.uptimeMillis(); Long crashTime; Long crashTimePersistent; if (!app.isolated) { crashTime = mProcessCrashTimes.get(app.info.processName, app.uid); crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid); } else { crashTime = crashTimePersistent = null; } if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) { // This process loses! Slog.w(TAG, "Process " + app.info.processName + " has crashed too many times: killing!"); EventLog.writeEvent( EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH, app.userId, app.info.processName, app.uid); mService.mStackSupervisor.handleAppCrashLocked(app); if (!app.persistent) { // We don't want to start this process again until the user // explicitly does so... but for persistent process, we really // need to keep it running. If a persistent process is actually // repeatedly crashing, then badness for everyone. EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid, app.info.processName); if (!app.isolated) { // XXX We don't have a way to mark isolated processes // as bad, since they don't have a peristent identity. mBadProcesses.put( app.info.processName, app.uid, new BadProcessInfo(now, shortMsg, longMsg, stackTrace)); mProcessCrashTimes.remove(app.info.processName, app.uid); } app.bad = true; app.removed = true; // Don't let services in this process be restarted and potentially // annoy the user repeatedly. Unless it is persistent, since those // processes run critical code. mService.removeProcessLocked(app, false, false, "crash"); mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); return false; } mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); } else { TaskRecord affectedTask = mService.mStackSupervisor.finishTopRunningActivityLocked(app, reason); if (data != null) { data.task = affectedTask; } if (data != null && crashTimePersistent != null && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) { data.repeating = true; } } // Bump up the crash count of any services currently running in the proc. for (int i = app.services.size() - 1; i >= 0; i--) { // Any services running in the application need to be placed // back in the pending list. ServiceRecord sr = app.services.valueAt(i); sr.crashCount++; } // If the crashing process is what we consider to be the "home process" and it has been // replaced by a third-party app, clear the package preferred activities from packages // with a home activity running in the process to prevent a repeatedly crashing app // from blocking the user to manually clear the list. final ArrayList<ActivityRecord> activities = app.activities; if (app == mService.mHomeProcess && activities.size() > 0 && (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { final ActivityRecord r = activities.get(activityNdx); if (r.isHomeActivity()) { Log.i(TAG, "Clearing package preferred activities from " + r.packageName); try { ActivityThread.getPackageManager().clearPackagePreferredActivities(r.packageName); } catch (RemoteException c) { // pm is in same process, this will never happen. } } } } if (!app.isolated) { // XXX Can't keep track of crash times for isolated processes, // because they don't have a perisistent identity. mProcessCrashTimes.put(app.info.processName, app.uid, now); mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now); } if (app.crashHandler != null) mService.mHandler.post(app.crashHandler); return true; }
final void appNotResponding( ProcessRecord app, ActivityRecord activity, ActivityRecord parent, boolean aboveSystem, final String annotation) { ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20); if (mService.mController != null) { try { // 0 == continue, -1 = kill process immediately int res = mService.mController.appEarlyNotResponding(app.processName, app.pid, annotation); if (res < 0 && app.pid != MY_PID) { app.kill("anr", true); } } catch (RemoteException e) { mService.mController = null; Watchdog.getInstance().setActivityController(null); } } long anrTime = SystemClock.uptimeMillis(); if (ActivityManagerService.MONITOR_CPU_USAGE) { mService.updateCpuStatsNow(); } synchronized (mService) { // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down. if (mService.mShuttingDown) { Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation); return; } else if (app.notResponding) { Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation); return; } else if (app.crashing) { Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation); return; } else if (app.killedByAm) { Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation); return; } else if (app.killed) { Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation); return; } // In case we come through here for the same app before completing // this one, mark as anring now so we will bail out. app.notResponding = true; // Log the ANR to the event log. EventLog.writeEvent( EventLogTags.AM_ANR, app.userId, app.pid, app.processName, app.info.flags, annotation); // Dump thread traces as quickly as we can, starting with "interesting" processes. firstPids.add(app.pid); int parentPid = app.pid; if (parent != null && parent.app != null && parent.app.pid > 0) { parentPid = parent.app.pid; } if (parentPid != app.pid) firstPids.add(parentPid); if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID); for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mService.mLruProcesses.get(i); if (r != null && r.thread != null) { int pid = r.pid; if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) { if (r.persistent) { firstPids.add(pid); if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r); } else { lastPids.put(pid, Boolean.TRUE); if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r); } } } } } // Log the ANR to the main log. StringBuilder info = new StringBuilder(); info.setLength(0); info.append("ANR in ").append(app.processName); if (activity != null && activity.shortComponentName != null) { info.append(" (").append(activity.shortComponentName).append(")"); } info.append("\n"); info.append("PID: ").append(app.pid).append("\n"); if (annotation != null) { info.append("Reason: ").append(annotation).append("\n"); } if (parent != null && parent != activity) { info.append("Parent: ").append(parent.shortComponentName).append("\n"); } final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); File tracesFile = mService.dumpStackTraces( true, firstPids, processCpuTracker, lastPids, NATIVE_STACKS_OF_INTEREST); String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { mService.updateCpuStatsNow(); synchronized (mService.mProcessCpuTracker) { cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime); } info.append(processCpuTracker.printCurrentLoad()); info.append(cpuInfo); } info.append(processCpuTracker.printCurrentState(anrTime)); Slog.e(TAG, info.toString()); if (tracesFile == null) { // There is no trace file, so dump (only) the alleged culprit's threads to the log Process.sendSignal(app.pid, Process.SIGNAL_QUIT); } mService.addErrorToDropBox( "anr", app, app.processName, activity, parent, annotation, cpuInfo, tracesFile, null); if (mService.mController != null) { try { // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately int res = mService.mController.appNotResponding(app.processName, app.pid, info.toString()); if (res != 0) { if (res < 0 && app.pid != MY_PID) { app.kill("anr", true); } else { synchronized (mService) { mService.mServices.scheduleServiceTimeoutLocked(app); } } return; } } catch (RemoteException e) { mService.mController = null; Watchdog.getInstance().setActivityController(null); } } // Unless configured otherwise, swallow ANRs in background processes & kill the process. boolean showBackground = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; synchronized (mService) { mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid); if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) { app.kill("bg anr", true); return; } // Set the app's notResponding state, and look up the errorReportReceiver makeAppNotRespondingLocked( app, activity != null ? activity.shortComponentName : null, annotation != null ? "ANR " + annotation : "ANR", info.toString()); // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); HashMap<String, Object> map = new HashMap<String, Object>(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; msg.obj = map; msg.arg1 = aboveSystem ? 1 : 0; map.put("app", app); if (activity != null) { map.put("activity", activity); } mService.mUiHandler.sendMessage(msg); } }
/** Release occupied swip process record. */ public void releaseSwipOccupiedProcessLocked() { if (mSwipOccupiedProcess != null) { mSwipOccupiedProcess.releaseSwipListenerRecord(); mSwipOccupiedProcess = null; } }
final void processNextBroadcast(boolean fromMsg) { synchronized (mService) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v( TAG, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); mService.updateCpuStats(); if (fromMsg) { mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); mCurrentBroadcast = r; final int N = r.receivers.size(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i = 0; i < N; i++) { Object target = r.receivers.get(i); if (DEBUG_BROADCAST) Slog.v( TAG, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); deliverToRegisteredReceiverLocked(r, (BroadcastFilter) target, false); } addBroadcastToHistoryLocked(r); mCurrentBroadcast = null; if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast [" + mQueueName + "] " + r); } // Now take care of the next serialized one... // If we are waiting for a process to come up to handle the next // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. if (mPendingBroadcast != null) { if (DEBUG_BROADCAST_LIGHT) { Slog.v( TAG, "processNextBroadcast [" + mQueueName + "]: waiting for " + mPendingBroadcast.curApp); } boolean isDead; synchronized (mService.mPidsSelfLocked) { isDead = (mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null); } if (!isDead) { // It's still alive, so keep waiting return; } else { Slog.w( TAG, "pending app [" + mQueueName + "]" + mPendingBroadcast.curApp + " died before responding to broadcast"); mPendingBroadcast.state = BroadcastRecord.IDLE; mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; do { if (mOrderedBroadcasts.size() == 0) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked(); if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); mCurrentBroadcast = r; boolean forceReceive = false; // Ensure that even if something goes awry with the timeout // detection, we catch "hung" broadcasts here, discard them, // and continue to make progress. // // This is only done if the system is ready so that PRE_BOOT_COMPLETED // receivers don't get executed with timeouts. They're intended for // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2 * mTimeoutPeriod * numReceivers))) { Slog.w( TAG, "Hung broadcast [" + mQueueName + "] discarded after timeout failure:" + " now=" + now + " dispatchTime=" + r.dispatchTime + " startTime=" + r.receiverTime + " intent=" + r.intent + " numReceivers=" + numReceivers + " nextReceiver=" + r.nextReceiver + " state=" + r.state); broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { if (DEBUG_BROADCAST) Slog.d( TAG, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { if (DEBUG_BROADCAST) { int seq = r.intent.getIntExtra("seq", -1); Slog.i( TAG, "Finishing broadcast [" + mQueueName + "] " + r.intent.getAction() + " seq=" + seq + " app=" + r.callerApp); } performReceiveLocked( r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isnt kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { Slog.w( TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e); } } if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG"); cancelBroadcastTimeoutLocked(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast " + r); // ... and on to the next... addBroadcastToHistoryLocked(r); mOrderedBroadcasts.remove(0); mCurrentBroadcast = null; r = null; looped = true; continue; } } while (r == null); // Get the next receiver... int recIdx = r.nextReceiver++; // Keep track of when this receiver started, and make sure there // is a timeout message pending to kill it if need be. r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast [" + mQueueName + "] " + r); } if (!mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; if (DEBUG_BROADCAST) Slog.v( TAG, "Submitting BROADCAST_TIMEOUT_MSG [" + mQueueName + "] for " + r + " at " + timeoutTime); setBroadcastTimeoutLocked(timeoutTime); } Object nextReceiver = r.receivers.get(recIdx); if (nextReceiver instanceof BroadcastFilter) { // Simple case: this is a registered receiver who gets // a direct call. BroadcastFilter filter = (BroadcastFilter) nextReceiver; if (DEBUG_BROADCAST) Slog.v(TAG, "Delivering ordered [" + mQueueName + "] to registered " + filter + ": " + r); deliverToRegisteredReceiverLocked(r, filter, r.ordered); if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. if (DEBUG_BROADCAST) Slog.v( TAG, "Quick finishing [" + mQueueName + "]: ordered=" + r.ordered + " receiver=" + r.receiver); r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } return; } // Hard case: need to instantiate the receiver, possibly // starting its application process to host it. ResolveInfo info = (ResolveInfo) nextReceiver; ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName, info.activityInfo.name); boolean skip = false; int perm = mService.checkComponentPermission( info.activityInfo.permission, r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, info.activityInfo.exported); if (perm != PackageManager.PERMISSION_GRANTED) { if (!info.activityInfo.exported) { Slog.w( TAG, "Permission Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + ")" + " is not exported from uid " + info.activityInfo.applicationInfo.uid + " due to receiver " + component.flattenToShortString()); } else { Slog.w( TAG, "Permission Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + ")" + " requires " + info.activityInfo.permission + " due to receiver " + component.flattenToShortString()); } skip = true; } if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && r.requiredPermission != null) { try { perm = AppGlobals.getPackageManager() .checkPermission( r.requiredPermission, info.activityInfo.applicationInfo.packageName); } catch (RemoteException e) { perm = PackageManager.PERMISSION_DENIED; } if (perm != PackageManager.PERMISSION_GRANTED) { Slog.w( TAG, "Permission Denial: receiving " + r.intent + " to " + component.flattenToShortString() + " requires " + r.requiredPermission + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; } } if (r.appOp != AppOpsManager.OP_NONE) { int mode = mService.mAppOpsService.checkOperation( r.appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName); if (mode != AppOpsManager.MODE_ALLOWED) { if (DEBUG_BROADCAST) Slog.v( TAG, "App op " + r.appOp + " not allowed for broadcast to uid " + info.activityInfo.applicationInfo.uid + " pkg " + info.activityInfo.packageName); skip = true; } } // MUTT if (mMuttFilter.hasAction(r.intent.getAction())) { Slog.v(TAG, "MUTT: whitelist broadcast " + r.intent.toString()); } else { if (mService.mBatteryStatsService.allowMutt( info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) != 0) { Slog.w( TAG, "MUTT: skipping broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + " to " + component.flattenToShortString() + ")"); skip = true; } } boolean isSingleton = false; try { isSingleton = mService.isSingleton( info.activityInfo.processName, info.activityInfo.applicationInfo, info.activityInfo.name, info.activityInfo.flags); } catch (SecurityException e) { Slog.w(TAG, e.getMessage()); skip = true; } if ((info.activityInfo.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { if (ActivityManager.checkUidPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, info.activityInfo.applicationInfo.uid) != PackageManager.PERMISSION_GRANTED) { Slog.w( TAG, "Permission Denial: Receiver " + component.flattenToShortString() + " requests FLAG_SINGLE_USER, but app does not hold " + android.Manifest.permission.INTERACT_ACROSS_USERS); skip = true; } } if (r.curApp != null && r.curApp.crashing) { // If the target process is crashing, just skip it. if (DEBUG_BROADCAST) Slog.v( TAG, "Skipping deliver ordered [" + mQueueName + "] " + r + " to " + r.curApp + ": process crashing"); skip = true; } if (skip) { if (DEBUG_BROADCAST) Slog.v( TAG, "Skipping delivery of ordered [" + mQueueName + "] " + r + " for whatever reason"); r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); return; } r.state = BroadcastRecord.APP_RECEIVE; String targetProcess = info.activityInfo.processName; r.curComponent = component; if (r.callingUid != Process.SYSTEM_UID && isSingleton) { info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); } r.curReceiver = info.activityInfo; if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) { Slog.v( TAG_MU, "Updated broadcast record activity info for secondary user, " + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = " + info.activityInfo.applicationInfo.uid); } // Broadcast is being executed, its package can't be stopped. try { AppGlobals.getPackageManager() .setPackageStoppedState( r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w( TAG, "Failed trying to unstop package " + r.curComponent.getPackageName() + ": " + e); } // Is this receiver's application already running? ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid); if (app != null && app.thread != null) { try { app.addPackage(info.activityInfo.packageName); processCurBroadcastLocked(r, app); return; } catch (RemoteException e) { Slog.w(TAG, "Exception when sending broadcast to " + r.curComponent, e); } catch (RuntimeException e) { Log.wtf(TAG, "Failed sending broadcast to " + r.curComponent + " with " + r.intent, e); // If some unexpected exception happened, just skip // this broadcast. At this point we are not in the call // from a client, so throwing an exception out from here // will crash the entire system instead of just whoever // sent the broadcast. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; return; } // If a dead object exception was thrown -- fall through to // restart the application. } // Not running -- get it started, to be executed when the app comes up. if (DEBUG_BROADCAST) Slog.v( TAG, "Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r); if ((r.curApp = mService.startProcessLocked( targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Slog.w( TAG, "Unable to launch app " + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad"); logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, true); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx; } }