Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 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.rollback; |
| 18 | |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 19 | import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; |
| 20 | import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; |
| 21 | import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; |
| 22 | import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; |
| 23 | import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; |
| 24 | |
| 25 | import android.annotation.NonNull; |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 26 | import android.annotation.Nullable; |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 27 | import android.content.BroadcastReceiver; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 28 | import android.content.Context; |
| 29 | import android.content.Intent; |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 30 | import android.content.IntentFilter; |
| 31 | import android.content.pm.PackageInstaller; |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 32 | import android.content.pm.PackageManager; |
Zimuzo | c119780 | 2019-01-30 12:05:41 +0000 | [diff] [blame] | 33 | import android.content.pm.VersionedPackage; |
Richard Uhler | 0e96192 | 2019-01-25 13:07:08 +0000 | [diff] [blame] | 34 | import android.content.rollback.PackageRollbackInfo; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 35 | import android.content.rollback.RollbackInfo; |
| 36 | import android.content.rollback.RollbackManager; |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 37 | import android.os.Environment; |
| 38 | import android.os.FileUtils; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 39 | import android.os.Handler; |
| 40 | import android.os.HandlerThread; |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 41 | import android.os.PowerManager; |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 42 | import android.os.SystemProperties; |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 43 | import android.text.TextUtils; |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 44 | import android.util.ArraySet; |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 45 | import android.util.Slog; |
| 46 | import android.util.StatsLog; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 47 | |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 48 | import com.android.internal.R; |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 49 | import com.android.internal.annotations.GuardedBy; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 50 | import com.android.server.PackageWatchdog; |
Gavin Corkery | f305f4d | 2019-11-27 15:46:29 +0000 | [diff] [blame] | 51 | import com.android.server.PackageWatchdog.FailureReasons; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 52 | import com.android.server.PackageWatchdog.PackageHealthObserver; |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 53 | import com.android.server.PackageWatchdog.PackageHealthObserverImpact; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 54 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 55 | import libcore.io.IoUtils; |
| 56 | |
| 57 | import java.io.File; |
| 58 | import java.io.FileOutputStream; |
| 59 | import java.io.IOException; |
| 60 | import java.io.PrintWriter; |
Richard Uhler | bf5b5c4 | 2019-01-28 15:26:37 +0000 | [diff] [blame] | 61 | import java.util.Collections; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 62 | import java.util.List; |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 63 | import java.util.Set; |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 64 | import java.util.concurrent.TimeUnit; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 65 | |
| 66 | /** |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 67 | * {@link PackageHealthObserver} for {@link RollbackManagerService}. |
| 68 | * This class monitors crashes and triggers RollbackManager rollback accordingly. |
| 69 | * It also monitors native crashes for some short while after boot. |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 70 | * |
| 71 | * @hide |
| 72 | */ |
| 73 | public final class RollbackPackageHealthObserver implements PackageHealthObserver { |
| 74 | private static final String TAG = "RollbackPackageHealthObserver"; |
| 75 | private static final String NAME = "rollback-observer"; |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 76 | private static final int INVALID_ROLLBACK_ID = -1; |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 77 | // TODO: make the following values configurable via DeviceConfig |
| 78 | private static final long NATIVE_CRASH_POLLING_INTERVAL_MILLIS = |
| 79 | TimeUnit.SECONDS.toMillis(30); |
| 80 | private static final long NUMBER_OF_NATIVE_CRASH_POLLS = 10; |
| 81 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 82 | private final Context mContext; |
| 83 | private final Handler mHandler; |
| 84 | private final File mLastStagedRollbackIdFile; |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 85 | // Staged rollback ids that have been committed but their session is not yet ready |
| 86 | @GuardedBy("mPendingStagedRollbackIds") |
| 87 | private final Set<Integer> mPendingStagedRollbackIds = new ArraySet<>(); |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 88 | // this field is initialized in the c'tor and then only accessed from mHandler thread, so |
| 89 | // no need to guard with a lock |
| 90 | private long mNumberOfNativeCrashPollsRemaining; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 91 | |
| 92 | RollbackPackageHealthObserver(Context context) { |
| 93 | mContext = context; |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 94 | mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 95 | HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver"); |
| 96 | handlerThread.start(); |
| 97 | mHandler = handlerThread.getThreadHandler(); |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 98 | File dataDir = new File(Environment.getDataDirectory(), "rollback-observer"); |
| 99 | dataDir.mkdirs(); |
| 100 | mLastStagedRollbackIdFile = new File(dataDir, "last-staged-rollback-id"); |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 101 | PackageWatchdog.getInstance(mContext).registerHealthObserver(this); |
| 102 | } |
| 103 | |
| 104 | @Override |
Zimuzo | 71d931e | 2019-02-01 13:08:16 +0000 | [diff] [blame] | 105 | public int onHealthCheckFailed(VersionedPackage failedPackage) { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 106 | if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage) |
| 107 | == null) { |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 108 | // Don't handle the notification, no rollbacks available for the package |
| 109 | return PackageHealthObserverImpact.USER_IMPACT_NONE; |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 110 | } else { |
| 111 | // Rollback is available, we may get a callback into #execute |
| 112 | return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 113 | } |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | @Override |
Gavin Corkery | f305f4d | 2019-11-27 15:46:29 +0000 | [diff] [blame] | 117 | public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) { |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 118 | RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 119 | VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); |
| 120 | RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage); |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 121 | int reasonToLog = mapFailureReasonToMetric(rollbackReason); |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 122 | |
| 123 | if (rollback == null) { |
Zimuzo | 9e57ecb | 2019-02-04 15:34:08 +0000 | [diff] [blame] | 124 | Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ " |
Zimuzo | 71d931e | 2019-02-01 13:08:16 +0000 | [diff] [blame] | 125 | + failedPackage.getPackageName() + "] with versionCode: [" |
| 126 | + failedPackage.getVersionCode() + "]"); |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 127 | return false; |
| 128 | } |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 129 | |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 130 | logEvent(moduleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 131 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, |
| 132 | reasonToLog, failedPackage.getPackageName()); |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 133 | LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 134 | int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, |
| 135 | RollbackManager.STATUS_FAILURE); |
| 136 | if (status == RollbackManager.STATUS_SUCCESS) { |
| 137 | if (rollback.isStaged()) { |
| 138 | int rollbackId = rollback.getRollbackId(); |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 139 | synchronized (mPendingStagedRollbackIds) { |
| 140 | mPendingStagedRollbackIds.add(rollbackId); |
| 141 | } |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 142 | BroadcastReceiver listener = |
| 143 | listenForStagedSessionReady(rollbackManager, rollbackId, |
| 144 | moduleMetadataPackage); |
| 145 | handleStagedSessionChange(rollbackManager, rollbackId, listener, |
| 146 | moduleMetadataPackage); |
Zimuzo | 9e57ecb | 2019-02-04 15:34:08 +0000 | [diff] [blame] | 147 | } else { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 148 | logEvent(moduleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 149 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, |
| 150 | reasonToLog, failedPackage.getPackageName()); |
Zimuzo | 9e57ecb | 2019-02-04 15:34:08 +0000 | [diff] [blame] | 151 | } |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 152 | } else { |
| 153 | logEvent(moduleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 154 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, |
| 155 | reasonToLog, failedPackage.getPackageName()); |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 156 | } |
| 157 | }); |
| 158 | |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 159 | mHandler.post(() -> |
Zimuzo | c119780 | 2019-01-30 12:05:41 +0000 | [diff] [blame] | 160 | rollbackManager.commitRollback(rollback.getRollbackId(), |
Zimuzo | 9e57ecb | 2019-02-04 15:34:08 +0000 | [diff] [blame] | 161 | Collections.singletonList(failedPackage), |
Richard Uhler | e87368e | 2019-01-24 16:34:14 +0000 | [diff] [blame] | 162 | rollbackReceiver.getIntentSender())); |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 163 | // Assume rollback executed successfully |
| 164 | return true; |
| 165 | } |
| 166 | |
| 167 | @Override |
| 168 | public String getName() { |
| 169 | return NAME; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Start observing health of {@code packages} for {@code durationMs}. |
| 174 | * This may cause {@code packages} to be rolled back if they crash too freqeuntly. |
| 175 | */ |
| 176 | public void startObservingHealth(List<String> packages, long durationMs) { |
Zimuzo | caa435e | 2019-03-20 11:16:06 +0000 | [diff] [blame] | 177 | PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs); |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 178 | } |
| 179 | |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 180 | /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot |
| 181 | * to check for native crashes and mitigate them if needed. |
| 182 | */ |
| 183 | public void onBootCompletedAsync() { |
| 184 | mHandler.post(()->onBootCompleted()); |
| 185 | } |
| 186 | |
| 187 | private void onBootCompleted() { |
| 188 | RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); |
| 189 | PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); |
| 190 | String moduleMetadataPackageName = getModuleMetadataPackageName(); |
| 191 | VersionedPackage newModuleMetadataPackage = getModuleMetadataPackage(); |
| 192 | |
| 193 | if (getAvailableRollback(rollbackManager, newModuleMetadataPackage) != null) { |
| 194 | scheduleCheckAndMitigateNativeCrashes(); |
| 195 | } |
| 196 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 197 | int rollbackId = popLastStagedRollbackId(); |
| 198 | if (rollbackId == INVALID_ROLLBACK_ID) { |
| 199 | // No staged rollback before reboot |
| 200 | return; |
| 201 | } |
| 202 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 203 | RollbackInfo rollback = null; |
| 204 | for (RollbackInfo info : rollbackManager.getRecentlyCommittedRollbacks()) { |
| 205 | if (rollbackId == info.getRollbackId()) { |
| 206 | rollback = info; |
| 207 | break; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | if (rollback == null) { |
| 212 | Slog.e(TAG, "rollback info not found for last staged rollback: " + rollbackId); |
| 213 | return; |
| 214 | } |
| 215 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 216 | // Use the version of the metadata package that was installed before |
| 217 | // we rolled back for logging purposes. |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 218 | VersionedPackage oldModuleMetadataPackage = null; |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 219 | for (PackageRollbackInfo packageRollback : rollback.getPackages()) { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 220 | if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) { |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 221 | oldModuleMetadataPackage = packageRollback.getVersionRolledBackFrom(); |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 222 | break; |
| 223 | } |
| 224 | } |
| 225 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 226 | int sessionId = rollback.getCommittedSessionId(); |
| 227 | PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); |
| 228 | if (sessionInfo == null) { |
| 229 | Slog.e(TAG, "On boot completed, could not load session id " + sessionId); |
| 230 | return; |
| 231 | } |
| 232 | if (sessionInfo.isStagedSessionApplied()) { |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 233 | logEvent(oldModuleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 234 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, |
| 235 | WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 236 | } else if (sessionInfo.isStagedSessionReady()) { |
| 237 | // TODO: What do for staged session ready but not applied |
| 238 | } else { |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 239 | logEvent(oldModuleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 240 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, |
| 241 | WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 242 | } |
| 243 | } |
| 244 | |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 245 | private RollbackInfo getAvailableRollback(RollbackManager rollbackManager, |
| 246 | VersionedPackage failedPackage) { |
Zimuzo | c119780 | 2019-01-30 12:05:41 +0000 | [diff] [blame] | 247 | for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) { |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 248 | for (PackageRollbackInfo packageRollback : rollback.getPackages()) { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 249 | boolean hasFailedPackage = packageRollback.getPackageName().equals( |
Zimuzo | 71d931e | 2019-02-01 13:08:16 +0000 | [diff] [blame] | 250 | failedPackage.getPackageName()) |
Zimuzo | 972e1cd | 2019-01-28 16:30:01 +0000 | [diff] [blame] | 251 | && packageRollback.getVersionRolledBackFrom().getVersionCode() |
Zimuzo | 71d931e | 2019-02-01 13:08:16 +0000 | [diff] [blame] | 252 | == failedPackage.getVersionCode(); |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 253 | if (hasFailedPackage) { |
| 254 | return rollback; |
| 255 | } |
Zimuzo | e5009cd | 2019-01-23 18:11:58 +0000 | [diff] [blame] | 256 | } |
| 257 | } |
| 258 | return null; |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 259 | } |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 260 | |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 261 | @Nullable |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 262 | private String getModuleMetadataPackageName() { |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 263 | String packageName = mContext.getResources().getString( |
| 264 | R.string.config_defaultModuleMetadataProvider); |
Zimuzo | 9e57ecb | 2019-02-04 15:34:08 +0000 | [diff] [blame] | 265 | if (TextUtils.isEmpty(packageName)) { |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 266 | return null; |
| 267 | } |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 268 | return packageName; |
| 269 | } |
| 270 | |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 271 | @Nullable |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 272 | private VersionedPackage getModuleMetadataPackage() { |
| 273 | String packageName = getModuleMetadataPackageName(); |
| 274 | if (packageName == null) { |
| 275 | return null; |
| 276 | } |
Zimuzo | 03eeb13 | 2019-01-30 15:13:56 +0000 | [diff] [blame] | 277 | |
| 278 | try { |
| 279 | return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo( |
| 280 | packageName, 0 /* flags */).getLongVersionCode()); |
| 281 | } catch (PackageManager.NameNotFoundException e) { |
| 282 | Slog.w(TAG, "Module metadata provider not found"); |
| 283 | return null; |
| 284 | } |
| 285 | } |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 286 | |
| 287 | private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager, |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 288 | int rollbackId, VersionedPackage moduleMetadataPackage) { |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 289 | BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() { |
| 290 | @Override |
| 291 | public void onReceive(Context context, Intent intent) { |
| 292 | handleStagedSessionChange(rollbackManager, |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 293 | rollbackId, this /* BroadcastReceiver */, moduleMetadataPackage); |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 294 | } |
| 295 | }; |
| 296 | IntentFilter sessionUpdatedFilter = |
| 297 | new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED); |
| 298 | mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter); |
| 299 | return sessionUpdatedReceiver; |
| 300 | } |
| 301 | |
| 302 | private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId, |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 303 | BroadcastReceiver listener, VersionedPackage moduleMetadataPackage) { |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 304 | PackageInstaller packageInstaller = |
| 305 | mContext.getPackageManager().getPackageInstaller(); |
| 306 | List<RollbackInfo> recentRollbacks = |
| 307 | rollbackManager.getRecentlyCommittedRollbacks(); |
| 308 | for (int i = 0; i < recentRollbacks.size(); i++) { |
| 309 | RollbackInfo recentRollback = recentRollbacks.get(i); |
| 310 | int sessionId = recentRollback.getCommittedSessionId(); |
| 311 | if ((rollbackId == recentRollback.getRollbackId()) |
| 312 | && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) { |
| 313 | PackageInstaller.SessionInfo sessionInfo = |
| 314 | packageInstaller.getSessionInfo(sessionId); |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 315 | if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) { |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 316 | mContext.unregisterReceiver(listener); |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 317 | saveLastStagedRollbackId(rollbackId); |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 318 | logEvent(moduleMetadataPackage, |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 319 | StatsLog |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 320 | .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, |
| 321 | WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, |
| 322 | ""); |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 323 | mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 324 | } else if (sessionInfo.isStagedSessionFailed() |
| 325 | && markStagedSessionHandled(rollbackId)) { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 326 | logEvent(moduleMetadataPackage, |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 327 | StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, |
| 328 | WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, |
| 329 | ""); |
Zimuzo | ff99176 | 2019-02-01 19:25:44 +0000 | [diff] [blame] | 330 | mContext.unregisterReceiver(listener); |
| 331 | } |
| 332 | } |
| 333 | } |
| 334 | } |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 335 | |
Zimuzo | 8d231b4 | 2019-05-16 18:09:23 +0100 | [diff] [blame] | 336 | /** |
| 337 | * Returns {@code true} if staged session associated with {@code rollbackId} was marked |
| 338 | * as handled, {@code false} if already handled. |
| 339 | */ |
| 340 | private boolean markStagedSessionHandled(int rollbackId) { |
| 341 | synchronized (mPendingStagedRollbackIds) { |
| 342 | return mPendingStagedRollbackIds.remove(rollbackId); |
| 343 | } |
| 344 | } |
| 345 | |
Zimuzo | 841c494 | 2019-03-04 12:31:48 +0000 | [diff] [blame] | 346 | private void saveLastStagedRollbackId(int stagedRollbackId) { |
| 347 | try { |
| 348 | FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdFile); |
| 349 | PrintWriter pw = new PrintWriter(fos); |
| 350 | pw.println(stagedRollbackId); |
| 351 | pw.flush(); |
| 352 | FileUtils.sync(fos); |
| 353 | pw.close(); |
| 354 | } catch (IOException e) { |
| 355 | Slog.e(TAG, "Failed to save last staged rollback id", e); |
| 356 | mLastStagedRollbackIdFile.delete(); |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | private int popLastStagedRollbackId() { |
| 361 | int rollbackId = INVALID_ROLLBACK_ID; |
| 362 | if (!mLastStagedRollbackIdFile.exists()) { |
| 363 | return rollbackId; |
| 364 | } |
| 365 | |
| 366 | try { |
| 367 | rollbackId = Integer.parseInt( |
| 368 | IoUtils.readFileAsString(mLastStagedRollbackIdFile.getAbsolutePath()).trim()); |
| 369 | } catch (IOException | NumberFormatException e) { |
| 370 | Slog.e(TAG, "Failed to retrieve last staged rollback id", e); |
| 371 | } |
| 372 | mLastStagedRollbackIdFile.delete(); |
| 373 | return rollbackId; |
| 374 | } |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 375 | |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 376 | private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type, |
| 377 | int rollbackReason, @NonNull String failingPackageName) { |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 378 | Slog.i(TAG, "Watchdog event occurred of type: " + type); |
| 379 | if (moduleMetadataPackage != null) { |
Tej Singh | 73f8e9b | 2019-05-19 16:52:38 -0700 | [diff] [blame] | 380 | StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(), |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 381 | moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName); |
Zimuzo | da97236 | 2019-04-27 19:57:58 +0100 | [diff] [blame] | 382 | } |
| 383 | } |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 384 | |
| 385 | /** |
| 386 | * This method should be only called on mHandler thread, since it modifies |
| 387 | * {@link #mNumberOfNativeCrashPollsRemaining} and we want to keep this class lock free. |
| 388 | */ |
| 389 | private void checkAndMitigateNativeCrashes() { |
| 390 | mNumberOfNativeCrashPollsRemaining--; |
| 391 | // Check if native watchdog reported a crash |
Nikita Ioffe | 76a0579 | 2019-10-04 16:51:06 +0100 | [diff] [blame] | 392 | if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) { |
Gavin Corkery | f305f4d | 2019-11-27 15:46:29 +0000 | [diff] [blame] | 393 | execute(getModuleMetadataPackage(), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); |
shafik | c5805fb9 | 2019-04-29 20:08:07 +0100 | [diff] [blame] | 394 | // we stop polling after an attempt to execute rollback, regardless of whether the |
| 395 | // attempt succeeds or not |
| 396 | } else { |
| 397 | if (mNumberOfNativeCrashPollsRemaining > 0) { |
| 398 | mHandler.postDelayed(() -> checkAndMitigateNativeCrashes(), |
| 399 | NATIVE_CRASH_POLLING_INTERVAL_MILLIS); |
| 400 | } |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | /** |
| 405 | * Since this method can eventually trigger a RollbackManager rollback, it should be called |
| 406 | * only once boot has completed {@code onBootCompleted} and not earlier, because the install |
| 407 | * session must be entirely completed before we try to rollback. |
| 408 | */ |
| 409 | private void scheduleCheckAndMitigateNativeCrashes() { |
| 410 | Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check " |
| 411 | + "and mitigate native crashes"); |
| 412 | mHandler.post(()->checkAndMitigateNativeCrashes()); |
| 413 | } |
Gavin Corkery | dd1daba | 2019-11-27 19:11:13 +0000 | [diff] [blame] | 414 | |
| 415 | private int mapFailureReasonToMetric(@FailureReasons int failureReason) { |
| 416 | switch (failureReason) { |
| 417 | case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH: |
| 418 | return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; |
| 419 | case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK: |
| 420 | return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; |
| 421 | case PackageWatchdog.FAILURE_REASON_APP_CRASH: |
| 422 | return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; |
| 423 | case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING: |
| 424 | return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; |
| 425 | default: |
| 426 | return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; |
| 427 | } |
| 428 | } |
| 429 | |
Zimuzo | c4073cc | 2019-01-18 18:39:18 +0000 | [diff] [blame] | 430 | } |