blob: b84fd79c33fcdf81bbe833e5e89f5fda41dd21b8 [file] [log] [blame]
Zimuzoc4073cc2019-01-18 18:39:18 +00001/*
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
17package com.android.server.rollback;
18
Gavin Corkerydd1daba2019-11-27 19:11:13 +000019import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH;
20import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING;
21import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK;
22import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH;
23import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
24
25import android.annotation.NonNull;
Zimuzoda972362019-04-27 19:57:58 +010026import android.annotation.Nullable;
Zimuzoff991762019-02-01 19:25:44 +000027import android.content.BroadcastReceiver;
Zimuzoc4073cc2019-01-18 18:39:18 +000028import android.content.Context;
29import android.content.Intent;
Zimuzoff991762019-02-01 19:25:44 +000030import android.content.IntentFilter;
31import android.content.pm.PackageInstaller;
Zimuzo03eeb132019-01-30 15:13:56 +000032import android.content.pm.PackageManager;
Zimuzoc1197802019-01-30 12:05:41 +000033import android.content.pm.VersionedPackage;
Richard Uhler0e961922019-01-25 13:07:08 +000034import android.content.rollback.PackageRollbackInfo;
Zimuzoc4073cc2019-01-18 18:39:18 +000035import android.content.rollback.RollbackInfo;
36import android.content.rollback.RollbackManager;
Zimuzo841c4942019-03-04 12:31:48 +000037import android.os.Environment;
38import android.os.FileUtils;
Zimuzoc4073cc2019-01-18 18:39:18 +000039import android.os.Handler;
40import android.os.HandlerThread;
Zimuzoff991762019-02-01 19:25:44 +000041import android.os.PowerManager;
shafikc5805fb92019-04-29 20:08:07 +010042import android.os.SystemProperties;
Zimuzo03eeb132019-01-30 15:13:56 +000043import android.text.TextUtils;
Zimuzo8d231b42019-05-16 18:09:23 +010044import android.util.ArraySet;
Zimuzo03eeb132019-01-30 15:13:56 +000045import android.util.Slog;
46import android.util.StatsLog;
Zimuzoc4073cc2019-01-18 18:39:18 +000047
Zimuzo03eeb132019-01-30 15:13:56 +000048import com.android.internal.R;
Zimuzo8d231b42019-05-16 18:09:23 +010049import com.android.internal.annotations.GuardedBy;
Zimuzoc4073cc2019-01-18 18:39:18 +000050import com.android.server.PackageWatchdog;
Gavin Corkeryf305f4d2019-11-27 15:46:29 +000051import com.android.server.PackageWatchdog.FailureReasons;
Zimuzoc4073cc2019-01-18 18:39:18 +000052import com.android.server.PackageWatchdog.PackageHealthObserver;
Zimuzoe5009cd2019-01-23 18:11:58 +000053import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
Zimuzoc4073cc2019-01-18 18:39:18 +000054
Zimuzo841c4942019-03-04 12:31:48 +000055import libcore.io.IoUtils;
56
57import java.io.File;
58import java.io.FileOutputStream;
59import java.io.IOException;
60import java.io.PrintWriter;
Richard Uhlerbf5b5c42019-01-28 15:26:37 +000061import java.util.Collections;
Zimuzoc4073cc2019-01-18 18:39:18 +000062import java.util.List;
Zimuzo8d231b42019-05-16 18:09:23 +010063import java.util.Set;
shafikc5805fb92019-04-29 20:08:07 +010064import java.util.concurrent.TimeUnit;
Zimuzoc4073cc2019-01-18 18:39:18 +000065
66/**
shafikc5805fb92019-04-29 20:08:07 +010067 * {@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.
Zimuzoc4073cc2019-01-18 18:39:18 +000070 *
71 * @hide
72 */
73public final class RollbackPackageHealthObserver implements PackageHealthObserver {
74 private static final String TAG = "RollbackPackageHealthObserver";
75 private static final String NAME = "rollback-observer";
Zimuzo841c4942019-03-04 12:31:48 +000076 private static final int INVALID_ROLLBACK_ID = -1;
shafikc5805fb92019-04-29 20:08:07 +010077 // 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
Zimuzo841c4942019-03-04 12:31:48 +000082 private final Context mContext;
83 private final Handler mHandler;
84 private final File mLastStagedRollbackIdFile;
Zimuzo8d231b42019-05-16 18:09:23 +010085 // 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<>();
shafikc5805fb92019-04-29 20:08:07 +010088 // 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;
Zimuzoc4073cc2019-01-18 18:39:18 +000091
92 RollbackPackageHealthObserver(Context context) {
93 mContext = context;
shafikc5805fb92019-04-29 20:08:07 +010094 mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
Zimuzoc4073cc2019-01-18 18:39:18 +000095 HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
96 handlerThread.start();
97 mHandler = handlerThread.getThreadHandler();
Zimuzo841c4942019-03-04 12:31:48 +000098 File dataDir = new File(Environment.getDataDirectory(), "rollback-observer");
99 dataDir.mkdirs();
100 mLastStagedRollbackIdFile = new File(dataDir, "last-staged-rollback-id");
Zimuzoc4073cc2019-01-18 18:39:18 +0000101 PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
102 }
103
104 @Override
Zimuzo71d931e2019-02-01 13:08:16 +0000105 public int onHealthCheckFailed(VersionedPackage failedPackage) {
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000106 if (getAvailableRollback(failedPackage) == null) {
Zimuzoe5009cd2019-01-23 18:11:58 +0000107 // Don't handle the notification, no rollbacks available for the package
108 return PackageHealthObserverImpact.USER_IMPACT_NONE;
Zimuzoda972362019-04-27 19:57:58 +0100109 } else {
110 // Rollback is available, we may get a callback into #execute
111 return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
Zimuzoc4073cc2019-01-18 18:39:18 +0000112 }
Zimuzoe5009cd2019-01-23 18:11:58 +0000113 }
114
115 @Override
Gavin Corkeryf305f4d2019-11-27 15:46:29 +0000116 public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) {
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000117 RollbackInfo rollback = getAvailableRollback(failedPackage);
Zimuzoda972362019-04-27 19:57:58 +0100118 if (rollback == null) {
Zimuzo9e57ecb2019-02-04 15:34:08 +0000119 Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
Zimuzo71d931e2019-02-01 13:08:16 +0000120 + failedPackage.getPackageName() + "] with versionCode: ["
121 + failedPackage.getVersionCode() + "]");
Zimuzo03eeb132019-01-30 15:13:56 +0000122 return false;
123 }
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000124 rollbackPackage(rollback, failedPackage, rollbackReason);
Zimuzoe5009cd2019-01-23 18:11:58 +0000125 // Assume rollback executed successfully
126 return true;
127 }
128
129 @Override
130 public String getName() {
131 return NAME;
Zimuzoc4073cc2019-01-18 18:39:18 +0000132 }
133
134 /**
135 * Start observing health of {@code packages} for {@code durationMs}.
136 * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
137 */
138 public void startObservingHealth(List<String> packages, long durationMs) {
Zimuzocaa435e2019-03-20 11:16:06 +0000139 PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
Zimuzoc4073cc2019-01-18 18:39:18 +0000140 }
141
shafikc5805fb92019-04-29 20:08:07 +0100142 /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
143 * to check for native crashes and mitigate them if needed.
144 */
145 public void onBootCompletedAsync() {
146 mHandler.post(()->onBootCompleted());
147 }
148
149 private void onBootCompleted() {
150 RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
151 PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
152 String moduleMetadataPackageName = getModuleMetadataPackageName();
shafikc5805fb92019-04-29 20:08:07 +0100153
Mohammad Samiul Islama3f650d2019-12-10 12:09:54 +0000154 if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
shafikc5805fb92019-04-29 20:08:07 +0100155 scheduleCheckAndMitigateNativeCrashes();
156 }
157
Zimuzo841c4942019-03-04 12:31:48 +0000158 int rollbackId = popLastStagedRollbackId();
159 if (rollbackId == INVALID_ROLLBACK_ID) {
160 // No staged rollback before reboot
161 return;
162 }
163
Zimuzo841c4942019-03-04 12:31:48 +0000164 RollbackInfo rollback = null;
165 for (RollbackInfo info : rollbackManager.getRecentlyCommittedRollbacks()) {
166 if (rollbackId == info.getRollbackId()) {
167 rollback = info;
168 break;
169 }
170 }
171
172 if (rollback == null) {
173 Slog.e(TAG, "rollback info not found for last staged rollback: " + rollbackId);
174 return;
175 }
176
Zimuzo841c4942019-03-04 12:31:48 +0000177 // Use the version of the metadata package that was installed before
178 // we rolled back for logging purposes.
shafikc5805fb92019-04-29 20:08:07 +0100179 VersionedPackage oldModuleMetadataPackage = null;
Zimuzo841c4942019-03-04 12:31:48 +0000180 for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
Zimuzoda972362019-04-27 19:57:58 +0100181 if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) {
shafikc5805fb92019-04-29 20:08:07 +0100182 oldModuleMetadataPackage = packageRollback.getVersionRolledBackFrom();
Zimuzo841c4942019-03-04 12:31:48 +0000183 break;
184 }
185 }
186
Zimuzo841c4942019-03-04 12:31:48 +0000187 int sessionId = rollback.getCommittedSessionId();
188 PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
189 if (sessionInfo == null) {
190 Slog.e(TAG, "On boot completed, could not load session id " + sessionId);
191 return;
192 }
193 if (sessionInfo.isStagedSessionApplied()) {
shafikc5805fb92019-04-29 20:08:07 +0100194 logEvent(oldModuleMetadataPackage,
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000195 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
196 WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
Zimuzo841c4942019-03-04 12:31:48 +0000197 } else if (sessionInfo.isStagedSessionReady()) {
198 // TODO: What do for staged session ready but not applied
199 } else {
shafikc5805fb92019-04-29 20:08:07 +0100200 logEvent(oldModuleMetadataPackage,
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000201 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
202 WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
Zimuzo841c4942019-03-04 12:31:48 +0000203 }
204 }
205
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000206 private RollbackInfo getAvailableRollback(VersionedPackage failedPackage) {
207 RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
Zimuzoc1197802019-01-30 12:05:41 +0000208 for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
Zimuzoe5009cd2019-01-23 18:11:58 +0000209 for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
Zimuzoda972362019-04-27 19:57:58 +0100210 boolean hasFailedPackage = packageRollback.getPackageName().equals(
Zimuzo71d931e2019-02-01 13:08:16 +0000211 failedPackage.getPackageName())
Zimuzo972e1cd2019-01-28 16:30:01 +0000212 && packageRollback.getVersionRolledBackFrom().getVersionCode()
Zimuzo71d931e2019-02-01 13:08:16 +0000213 == failedPackage.getVersionCode();
Zimuzoda972362019-04-27 19:57:58 +0100214 if (hasFailedPackage) {
215 return rollback;
216 }
Zimuzoe5009cd2019-01-23 18:11:58 +0000217 }
218 }
219 return null;
Zimuzoc4073cc2019-01-18 18:39:18 +0000220 }
Zimuzo03eeb132019-01-30 15:13:56 +0000221
Zimuzoda972362019-04-27 19:57:58 +0100222 @Nullable
Zimuzo841c4942019-03-04 12:31:48 +0000223 private String getModuleMetadataPackageName() {
Zimuzo03eeb132019-01-30 15:13:56 +0000224 String packageName = mContext.getResources().getString(
225 R.string.config_defaultModuleMetadataProvider);
Zimuzo9e57ecb2019-02-04 15:34:08 +0000226 if (TextUtils.isEmpty(packageName)) {
Zimuzo03eeb132019-01-30 15:13:56 +0000227 return null;
228 }
Zimuzo841c4942019-03-04 12:31:48 +0000229 return packageName;
230 }
231
Zimuzoda972362019-04-27 19:57:58 +0100232 @Nullable
Zimuzo841c4942019-03-04 12:31:48 +0000233 private VersionedPackage getModuleMetadataPackage() {
234 String packageName = getModuleMetadataPackageName();
235 if (packageName == null) {
236 return null;
237 }
Zimuzo03eeb132019-01-30 15:13:56 +0000238
239 try {
240 return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
241 packageName, 0 /* flags */).getLongVersionCode());
242 } catch (PackageManager.NameNotFoundException e) {
243 Slog.w(TAG, "Module metadata provider not found");
244 return null;
245 }
246 }
Zimuzoff991762019-02-01 19:25:44 +0000247
248 private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000249 int rollbackId, @Nullable VersionedPackage moduleMetadataPackage) {
Zimuzoff991762019-02-01 19:25:44 +0000250 BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
251 @Override
252 public void onReceive(Context context, Intent intent) {
253 handleStagedSessionChange(rollbackManager,
Zimuzo841c4942019-03-04 12:31:48 +0000254 rollbackId, this /* BroadcastReceiver */, moduleMetadataPackage);
Zimuzoff991762019-02-01 19:25:44 +0000255 }
256 };
257 IntentFilter sessionUpdatedFilter =
258 new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
259 mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
260 return sessionUpdatedReceiver;
261 }
262
263 private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000264 BroadcastReceiver listener, @Nullable VersionedPackage moduleMetadataPackage) {
Zimuzoff991762019-02-01 19:25:44 +0000265 PackageInstaller packageInstaller =
266 mContext.getPackageManager().getPackageInstaller();
267 List<RollbackInfo> recentRollbacks =
268 rollbackManager.getRecentlyCommittedRollbacks();
269 for (int i = 0; i < recentRollbacks.size(); i++) {
270 RollbackInfo recentRollback = recentRollbacks.get(i);
271 int sessionId = recentRollback.getCommittedSessionId();
272 if ((rollbackId == recentRollback.getRollbackId())
273 && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
274 PackageInstaller.SessionInfo sessionInfo =
275 packageInstaller.getSessionInfo(sessionId);
Zimuzo8d231b42019-05-16 18:09:23 +0100276 if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) {
Zimuzoff991762019-02-01 19:25:44 +0000277 mContext.unregisterReceiver(listener);
Zimuzo841c4942019-03-04 12:31:48 +0000278 saveLastStagedRollbackId(rollbackId);
Zimuzoda972362019-04-27 19:57:58 +0100279 logEvent(moduleMetadataPackage,
Zimuzo841c4942019-03-04 12:31:48 +0000280 StatsLog
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000281 .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
282 WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
283 "");
Zimuzoff991762019-02-01 19:25:44 +0000284 mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
Zimuzo8d231b42019-05-16 18:09:23 +0100285 } else if (sessionInfo.isStagedSessionFailed()
286 && markStagedSessionHandled(rollbackId)) {
Zimuzoda972362019-04-27 19:57:58 +0100287 logEvent(moduleMetadataPackage,
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000288 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
289 WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
290 "");
Zimuzoff991762019-02-01 19:25:44 +0000291 mContext.unregisterReceiver(listener);
292 }
293 }
294 }
295 }
Zimuzo841c4942019-03-04 12:31:48 +0000296
Zimuzo8d231b42019-05-16 18:09:23 +0100297 /**
298 * Returns {@code true} if staged session associated with {@code rollbackId} was marked
299 * as handled, {@code false} if already handled.
300 */
301 private boolean markStagedSessionHandled(int rollbackId) {
302 synchronized (mPendingStagedRollbackIds) {
303 return mPendingStagedRollbackIds.remove(rollbackId);
304 }
305 }
306
Zimuzo841c4942019-03-04 12:31:48 +0000307 private void saveLastStagedRollbackId(int stagedRollbackId) {
308 try {
309 FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdFile);
310 PrintWriter pw = new PrintWriter(fos);
311 pw.println(stagedRollbackId);
312 pw.flush();
313 FileUtils.sync(fos);
314 pw.close();
315 } catch (IOException e) {
316 Slog.e(TAG, "Failed to save last staged rollback id", e);
317 mLastStagedRollbackIdFile.delete();
318 }
319 }
320
321 private int popLastStagedRollbackId() {
322 int rollbackId = INVALID_ROLLBACK_ID;
323 if (!mLastStagedRollbackIdFile.exists()) {
324 return rollbackId;
325 }
326
327 try {
328 rollbackId = Integer.parseInt(
329 IoUtils.readFileAsString(mLastStagedRollbackIdFile.getAbsolutePath()).trim());
330 } catch (IOException | NumberFormatException e) {
331 Slog.e(TAG, "Failed to retrieve last staged rollback id", e);
332 }
333 mLastStagedRollbackIdFile.delete();
334 return rollbackId;
335 }
Zimuzoda972362019-04-27 19:57:58 +0100336
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000337 private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type,
338 int rollbackReason, @NonNull String failingPackageName) {
Zimuzoda972362019-04-27 19:57:58 +0100339 Slog.i(TAG, "Watchdog event occurred of type: " + type);
340 if (moduleMetadataPackage != null) {
Tej Singh73f8e9b2019-05-19 16:52:38 -0700341 StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(),
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000342 moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName);
Zimuzoda972362019-04-27 19:57:58 +0100343 }
344 }
shafikc5805fb92019-04-29 20:08:07 +0100345
346 /**
347 * This method should be only called on mHandler thread, since it modifies
348 * {@link #mNumberOfNativeCrashPollsRemaining} and we want to keep this class lock free.
349 */
350 private void checkAndMitigateNativeCrashes() {
351 mNumberOfNativeCrashPollsRemaining--;
352 // Check if native watchdog reported a crash
Nikita Ioffe76a05792019-10-04 16:51:06 +0100353 if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000354 rollbackAll();
shafikc5805fb92019-04-29 20:08:07 +0100355 // we stop polling after an attempt to execute rollback, regardless of whether the
356 // attempt succeeds or not
357 } else {
358 if (mNumberOfNativeCrashPollsRemaining > 0) {
359 mHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
360 NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
361 }
362 }
363 }
364
365 /**
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000366 * Returns true if the package name is the name of a module.
367 */
368 private boolean isModule(String packageName) {
369 PackageManager pm = mContext.getPackageManager();
370 try {
371 return pm.getModuleInfo(packageName, 0) != null;
372 } catch (PackageManager.NameNotFoundException ignore) {
373 return false;
374 }
375 }
376
377 private VersionedPackage getVersionedPackage(String packageName) {
378 try {
379 return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
380 packageName, 0 /* flags */).getLongVersionCode());
381 } catch (PackageManager.NameNotFoundException e) {
382 return null;
383 }
384 }
385
386 /**
387 * Rolls back the session that owns {@code failedPackage}
388 *
389 * @param rollback {@code rollbackInfo} of the {@code failedPackage}
390 * @param failedPackage the package that needs to be rolled back
391 */
392 private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
393 @FailureReasons int rollbackReason) {
394 final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
395 int reasonToLog = mapFailureReasonToMetric(rollbackReason);
Gavin Corkerycf6a3992019-12-10 19:48:50 +0000396 final String failedPackageToLog;
397 if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
398 failedPackageToLog = SystemProperties.get(
399 "sys.init.updatable_crashing_process_name", "");
400 } else {
401 failedPackageToLog = failedPackage.getPackageName();
402 }
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000403 final VersionedPackage logPackage = isModule(failedPackage.getPackageName())
404 ? getModuleMetadataPackage()
405 : null;
406
407 logEvent(logPackage,
408 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
Gavin Corkerycf6a3992019-12-10 19:48:50 +0000409 reasonToLog, failedPackageToLog);
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000410 final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
411 int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
412 RollbackManager.STATUS_FAILURE);
413 if (status == RollbackManager.STATUS_SUCCESS) {
414 if (rollback.isStaged()) {
415 int rollbackId = rollback.getRollbackId();
416 synchronized (mPendingStagedRollbackIds) {
417 mPendingStagedRollbackIds.add(rollbackId);
418 }
419 BroadcastReceiver listener =
420 listenForStagedSessionReady(rollbackManager, rollbackId,
421 logPackage);
422 handleStagedSessionChange(rollbackManager, rollbackId, listener,
423 logPackage);
424 } else {
425 logEvent(logPackage,
426 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
Gavin Corkerycf6a3992019-12-10 19:48:50 +0000427 reasonToLog, failedPackageToLog);
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000428 }
429 } else {
430 logEvent(logPackage,
431 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
Gavin Corkerycf6a3992019-12-10 19:48:50 +0000432 reasonToLog, failedPackageToLog);
Mohammad Samiul Islam7bd87882019-11-21 17:16:41 +0000433 }
434 });
435
436 mHandler.post(() ->
437 rollbackManager.commitRollback(rollback.getRollbackId(),
438 Collections.singletonList(failedPackage),
439 rollbackReceiver.getIntentSender()));
440 }
441
442 private void rollbackAll() {
443 Slog.i(TAG, "Rolling back all available rollbacks");
444 RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
445 List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
446
447 for (RollbackInfo rollback : rollbacks) {
448 String samplePackageName = rollback.getPackages().get(0).getPackageName();
449 VersionedPackage sampleVersionedPackage = getVersionedPackage(samplePackageName);
450 if (sampleVersionedPackage == null) {
451 Slog.e(TAG, "Failed to rollback " + samplePackageName);
452 continue;
453 }
454 rollbackPackage(rollback, sampleVersionedPackage,
455 PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
456 }
457 }
458
459 /**
shafikc5805fb92019-04-29 20:08:07 +0100460 * Since this method can eventually trigger a RollbackManager rollback, it should be called
461 * only once boot has completed {@code onBootCompleted} and not earlier, because the install
462 * session must be entirely completed before we try to rollback.
463 */
464 private void scheduleCheckAndMitigateNativeCrashes() {
465 Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
466 + "and mitigate native crashes");
467 mHandler.post(()->checkAndMitigateNativeCrashes());
468 }
Gavin Corkerydd1daba2019-11-27 19:11:13 +0000469
470 private int mapFailureReasonToMetric(@FailureReasons int failureReason) {
471 switch (failureReason) {
472 case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH:
473 return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH;
474 case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK:
475 return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK;
476 case PackageWatchdog.FAILURE_REASON_APP_CRASH:
477 return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH;
478 case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING:
479 return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING;
480 default:
481 return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
482 }
483 }
484
Zimuzoc4073cc2019-01-18 18:39:18 +0000485}