1fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey/*
2fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * Copyright (C) 2017 The Android Open Source Project
3fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey *
4fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * you may not use this file except in compliance with the License.
6fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * You may obtain a copy of the License at
7fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey *
8fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey *
10fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * See the License for the specific language governing permissions and
14fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * limitations under the License.
15fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey */
16fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
17fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeypackage com.android.server;
18fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
19fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.content.ContentResolver;
20fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.content.Context;
219f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkeyimport android.os.Build;
228231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkeyimport android.os.Environment;
231bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkeyimport android.os.FileUtils;
24fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.os.RecoverySystem;
25fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.os.SystemClock;
26fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.os.SystemProperties;
27fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.os.UserHandle;
28fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.provider.Settings;
29fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.text.format.DateUtils;
30fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.util.ExceptionUtils;
31bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkeyimport android.util.Log;
32fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.util.MathUtils;
33fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.util.Slog;
34fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport android.util.SparseArray;
35fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
36fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
37bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkeyimport com.android.server.pm.PackageManagerService;
38fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
391bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkeyimport java.io.File;
40d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey
41fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey/**
42fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * Utilities to help rescue the system from crash loops. Callers are expected to
43fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * report boot events and persistent app crashes, and if they happen frequently
44fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * enough this class will slowly escalate through several rescue operations
45fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * before finally rebooting and prompting the user if they want to wipe data as
46fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * a last resort.
47fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey *
48fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey * @hide
49fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey */
50fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkeypublic class RescueParty {
51fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final String TAG = "RescueParty";
52fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
53bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey    private static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
549f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey    private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
55fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
56fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
57fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
58fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
59fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final int LEVEL_NONE = 0;
60fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
61fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
62fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
63fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final int LEVEL_FACTORY_RESET = 4;
64fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
65fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /** Threshold for boot loops */
66fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static final Threshold sBoot = new BootThreshold();
67fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /** Threshold for app crash loops */
68fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static SparseArray<Threshold> sApps = new SparseArray<>();
69fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
709f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey    private static boolean isDisabled() {
71bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey        // Check if we're explicitly enabled for testing
728231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey        if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
73bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey            return false;
74bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey        }
75bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey
76cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        // We're disabled on all engineering devices
77d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        if (Build.IS_ENG) {
78d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            Slog.v(TAG, "Disabled because of eng build");
79d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            return true;
80d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        }
81cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey
82cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        // We're disabled on userdebug devices connected over USB, since that's
83cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        // a decent signal that someone is actively trying to debug the device,
84cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        // or that it's in a lab environment.
85d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        if (Build.IS_USERDEBUG && isUsbActive()) {
86d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            Slog.v(TAG, "Disabled because of active USB connection");
87d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            return true;
88cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        }
89cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey
90cdee83a6147bf1601424d5451c30f0dfb8d0e2a6Jeff Sharkey        // One last-ditch check
91d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) {
92d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            Slog.v(TAG, "Disabled because of manual property");
93d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            return true;
94d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        }
95d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey
96d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        return false;
979f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey    }
989f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey
99fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
100fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Take note of a boot event. If we notice too many of these events
101fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * happening in rapid succession, we'll send out a rescue party.
102fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
103fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    public static void noteBoot(Context context) {
1049f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey        if (isDisabled()) return;
105fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        if (sBoot.incrementAndTest()) {
106fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            sBoot.reset();
107fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            incrementRescueLevel(sBoot.uid);
108fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            executeRescueLevel(context);
109fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
110fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
111fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
112fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
113fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Take note of a persistent app crash. If we notice too many of these
114fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * events happening in rapid succession, we'll send out a rescue party.
115fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
116fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    public static void notePersistentAppCrash(Context context, int uid) {
1179f1fc2d78743ce2d4de546c80d4f93c2ffcc8804Jeff Sharkey        if (isDisabled()) return;
118fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        Threshold t = sApps.get(uid);
119fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        if (t == null) {
120fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            t = new AppThreshold(uid);
121fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            sApps.put(uid, t);
122fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
123fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        if (t.incrementAndTest()) {
124fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            t.reset();
125fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            incrementRescueLevel(t.uid);
126fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            executeRescueLevel(context);
127fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
128fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
129fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
130fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
131fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Check if we're currently attempting to reboot for a factory reset.
132fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
133fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    public static boolean isAttemptingFactoryReset() {
134fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        return SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) == LEVEL_FACTORY_RESET;
135fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
136fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
137fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
138fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Escalate to the next rescue level. After incrementing the level you'll
139fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * probably want to call {@link #executeRescueLevel(Context)}.
140fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
141fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static void incrementRescueLevel(int triggerUid) {
142fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        final int level = MathUtils.constrain(
143fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
144fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                LEVEL_NONE, LEVEL_FACTORY_RESET);
145fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
146fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
147fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        EventLogTags.writeRescueLevel(level, triggerUid);
148bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey        PackageManagerService.logCriticalInfo(Log.WARN, "Incremented rescue level to "
149bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey                + levelToString(level) + " triggered by UID " + triggerUid);
150fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
151fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
152fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
153fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Called when {@code SettingsProvider} has been published, which is a good
154fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * opportunity to reset any settings depending on our rescue level.
155fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
156fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    public static void onSettingsProviderPublished(Context context) {
157fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        executeRescueLevel(context);
158fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
159fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
160fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static void executeRescueLevel(Context context) {
161fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
162fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        if (level == LEVEL_NONE) return;
163fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
164fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        Slog.w(TAG, "Attempting rescue level " + levelToString(level));
165fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        try {
166fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            executeRescueLevelInternal(context, level);
167fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            EventLogTags.writeRescueSuccess(level);
168bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey            PackageManagerService.logCriticalInfo(Log.DEBUG,
169bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey                    "Finished rescue level " + levelToString(level));
170fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        } catch (Throwable t) {
171bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey            final String msg = ExceptionUtils.getCompleteMessage(t);
172bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey            EventLogTags.writeRescueFailure(level, msg);
173bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey            PackageManagerService.logCriticalInfo(Log.ERROR,
174bc9caa1a2a38e23f7a6b61bcda81b5759e45ec66Jeff Sharkey                    "Failed rescue level " + levelToString(level) + ": " + msg);
175fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
176fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
177fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
178fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static void executeRescueLevelInternal(Context context, int level) throws Exception {
179fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        switch (level) {
180fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
181fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
182fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                break;
183fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
184fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES);
185fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                break;
186fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
187fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS);
188fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                break;
189fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_FACTORY_RESET:
190fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
191fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                break;
192fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
193fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
194fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
195fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static void resetAllSettings(Context context, int mode) throws Exception {
196fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        // Try our best to reset all settings possible, and once finished
197fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        // rethrow any exception that we encountered
198fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        Exception res = null;
199fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        final ContentResolver resolver = context.getContentResolver();
200fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        try {
201fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
202d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        } catch (Throwable t) {
203d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            res = new RuntimeException("Failed to reset global settings", t);
204fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
2058231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey        for (int userId : getAllUserIds()) {
206fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            try {
207fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
208d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            } catch (Throwable t) {
209d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey                res = new RuntimeException("Failed to reset secure settings for " + userId, t);
210fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            }
211fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
212fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        if (res != null) {
213fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            throw res;
214fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
215fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
216fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
217fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
218fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Threshold that can be triggered if a number of events occur within a
219fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * window of time.
220fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
221fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private abstract static class Threshold {
222fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public abstract int getCount();
223fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public abstract void setCount(int count);
224fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public abstract long getStart();
225fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public abstract void setStart(long start);
226fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
227fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        private final int uid;
228fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        private final int triggerCount;
229fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        private final long triggerWindow;
230fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
231fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public Threshold(int uid, int triggerCount, long triggerWindow) {
232fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            this.uid = uid;
233fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            this.triggerCount = triggerCount;
234fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            this.triggerWindow = triggerWindow;
235fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
236fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
237fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public void reset() {
238fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            setCount(0);
239fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            setStart(0);
240fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
241fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
242fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        /**
243fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey         * @return if this threshold has been triggered
244fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey         */
245fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public boolean incrementAndTest() {
246fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            final long now = SystemClock.elapsedRealtime();
247fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            final long window = now - getStart();
248fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            if (window > triggerWindow) {
249fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                setCount(1);
250fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                setStart(now);
251fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                return false;
252fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            } else {
253fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                int count = getCount() + 1;
254fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                setCount(count);
255fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                EventLogTags.writeRescueNote(uid, count, window);
256fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                Slog.w(TAG, "Noticed " + count + " events for UID " + uid + " in last "
257fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                        + (window / 1000) + " sec");
258fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                return (count >= triggerCount);
259fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            }
260fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
261fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
262fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
263fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
264fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Specialization of {@link Threshold} for monitoring boot events. It stores
265fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * counters in system properties for robustness.
266fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
267fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static class BootThreshold extends Threshold {
268fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public BootThreshold() {
269fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            // We're interested in 5 events in any 300 second period; this
270fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            // window is super relaxed because booting can take a long time if
271fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            // forced to dexopt things.
272fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            super(android.os.Process.ROOT_UID, 5, 300 * DateUtils.SECOND_IN_MILLIS);
273fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
274fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
275fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override
276fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public int getCount() {
277fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            return SystemProperties.getInt(PROP_RESCUE_BOOT_COUNT, 0);
278fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
279fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
280fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override
281fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public void setCount(int count) {
282fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            SystemProperties.set(PROP_RESCUE_BOOT_COUNT, Integer.toString(count));
283fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
284fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
285fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override
286fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public long getStart() {
287fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            return SystemProperties.getLong(PROP_RESCUE_BOOT_START, 0);
288fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
289fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
290fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override
291fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public void setStart(long start) {
292fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            SystemProperties.set(PROP_RESCUE_BOOT_START, Long.toString(start));
293fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
294fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
295fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
296fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    /**
297fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * Specialization of {@link Threshold} for monitoring app crashes. It stores
298fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     * counters in memory.
299fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey     */
300fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static class AppThreshold extends Threshold {
301fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        private int count;
302fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        private long start;
303fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
304fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        public AppThreshold(int uid) {
305fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            // We're interested in 5 events in any 30 second period; apps crash
306fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            // pretty quickly so we can keep a tight leash on them.
307fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            super(uid, 5, 30 * DateUtils.SECOND_IN_MILLIS);
308fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
309fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
310fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override public int getCount() { return count; }
311fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override public void setCount(int count) { this.count = count; }
312fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override public long getStart() { return start; }
313fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        @Override public void setStart(long start) { this.start = start; }
314fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
315fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
3168231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey    private static int[] getAllUserIds() {
317fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        int[] userIds = { UserHandle.USER_SYSTEM };
318fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        try {
3198231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey            for (File file : FileUtils.listFilesOrEmpty(Environment.getDataSystemDeDirectory())) {
3208231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                try {
3218231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                    final int userId = Integer.parseInt(file.getName());
3228231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                    if (userId != UserHandle.USER_SYSTEM) {
3238231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                        userIds = ArrayUtils.appendInt(userIds, userId);
3248231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                    }
3258231146d4ede7f0c0767da2bfdea58745611417cJeff Sharkey                } catch (NumberFormatException ignored) {
326fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey                }
327fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            }
328fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        } catch (Throwable t) {
329fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            Slog.w(TAG, "Trouble discovering users", t);
330fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
331fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        return userIds;
332fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
333fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey
334d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey    /**
335d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey     * Hacky test to check if the device has an active USB connection, which is
3361bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkey     * a good proxy for someone doing local development work.
337d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey     */
338d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey    private static boolean isUsbActive() {
339d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        try {
3401bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkey            final String state = FileUtils
3411bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkey                    .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, "");
3421bec44836ed6b29e128849b7be34dc7b2a214e76Jeff Sharkey            return "CONFIGURED".equals(state.trim());
343d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        } catch (Throwable t) {
344d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            Slog.w(TAG, "Failed to determine if device was on USB", t);
345d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey            return false;
346d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey        }
347d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey    }
348d9574c7bbf23ca282b93b1297e936a3d2e98e78aJeff Sharkey
349fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    private static String levelToString(int level) {
350fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        switch (level) {
351fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_NONE: return "NONE";
352fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
353fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
354fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
355fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
356fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey            default: return Integer.toString(level);
357fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey        }
358fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey    }
359fe6f85cac9e823fd33a134f7129fdf7310703293Jeff Sharkey}
360