blob: d24f21781b3988408dff98339a04776ae9b4a101 [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
Zimuzoff991762019-02-01 19:25:44 +000019import android.content.BroadcastReceiver;
Zimuzoc4073cc2019-01-18 18:39:18 +000020import android.content.Context;
21import android.content.Intent;
Zimuzoff991762019-02-01 19:25:44 +000022import android.content.IntentFilter;
23import android.content.pm.PackageInstaller;
Zimuzo03eeb132019-01-30 15:13:56 +000024import android.content.pm.PackageManager;
Zimuzoc1197802019-01-30 12:05:41 +000025import android.content.pm.VersionedPackage;
Richard Uhler0e961922019-01-25 13:07:08 +000026import android.content.rollback.PackageRollbackInfo;
Zimuzoc4073cc2019-01-18 18:39:18 +000027import android.content.rollback.RollbackInfo;
28import android.content.rollback.RollbackManager;
29import android.os.Handler;
30import android.os.HandlerThread;
Zimuzoff991762019-02-01 19:25:44 +000031import android.os.PowerManager;
Zimuzo03eeb132019-01-30 15:13:56 +000032import android.text.TextUtils;
Zimuzo9e57ecb2019-02-04 15:34:08 +000033import android.util.Pair;
Zimuzo03eeb132019-01-30 15:13:56 +000034import android.util.Slog;
35import android.util.StatsLog;
Zimuzoc4073cc2019-01-18 18:39:18 +000036
Zimuzo03eeb132019-01-30 15:13:56 +000037import com.android.internal.R;
Zimuzoc4073cc2019-01-18 18:39:18 +000038import com.android.server.PackageWatchdog;
39import com.android.server.PackageWatchdog.PackageHealthObserver;
Zimuzoe5009cd2019-01-23 18:11:58 +000040import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
Zimuzoc4073cc2019-01-18 18:39:18 +000041
Richard Uhlerbf5b5c42019-01-28 15:26:37 +000042import java.util.Collections;
Zimuzoc4073cc2019-01-18 18:39:18 +000043import java.util.List;
44
45/**
46 * {@code PackageHealthObserver} for {@code RollbackManagerService}.
47 *
48 * @hide
49 */
50public final class RollbackPackageHealthObserver implements PackageHealthObserver {
51 private static final String TAG = "RollbackPackageHealthObserver";
52 private static final String NAME = "rollback-observer";
53 private Context mContext;
54 private Handler mHandler;
55
56 RollbackPackageHealthObserver(Context context) {
57 mContext = context;
58 HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
59 handlerThread.start();
60 mHandler = handlerThread.getThreadHandler();
61 PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
62 }
63
64 @Override
Zimuzo71d931e2019-02-01 13:08:16 +000065 public int onHealthCheckFailed(VersionedPackage failedPackage) {
Zimuzo03eeb132019-01-30 15:13:56 +000066 VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
67 if (moduleMetadataPackage == null) {
68 // Ignore failure, no mainline update available
69 return PackageHealthObserverImpact.USER_IMPACT_NONE;
70 }
71
Zimuzo9e57ecb2019-02-04 15:34:08 +000072 if (getAvailableRollback(mContext.getSystemService(RollbackManager.class),
73 failedPackage, moduleMetadataPackage) == null) {
Zimuzoe5009cd2019-01-23 18:11:58 +000074 // Don't handle the notification, no rollbacks available for the package
75 return PackageHealthObserverImpact.USER_IMPACT_NONE;
Zimuzoc4073cc2019-01-18 18:39:18 +000076 }
Zimuzoe5009cd2019-01-23 18:11:58 +000077 // Rollback is available, we may get a callback into #execute
78 return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
79 }
80
81 @Override
Zimuzo71d931e2019-02-01 13:08:16 +000082 public boolean execute(VersionedPackage failedPackage) {
Zimuzo03eeb132019-01-30 15:13:56 +000083 VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
84 if (moduleMetadataPackage == null) {
85 // Ignore failure, no mainline update available
Zimuzoe5009cd2019-01-23 18:11:58 +000086 return false;
87 }
88
Zimuzo03eeb132019-01-30 15:13:56 +000089 RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
Zimuzo9e57ecb2019-02-04 15:34:08 +000090 Pair<RollbackInfo, Boolean> rollbackPair = getAvailableRollback(rollbackManager,
Zimuzo71d931e2019-02-01 13:08:16 +000091 failedPackage, moduleMetadataPackage);
Zimuzo9e57ecb2019-02-04 15:34:08 +000092 if (rollbackPair == null) {
93 Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
Zimuzo71d931e2019-02-01 13:08:16 +000094 + failedPackage.getPackageName() + "] with versionCode: ["
95 + failedPackage.getVersionCode() + "]");
Zimuzo03eeb132019-01-30 15:13:56 +000096 return false;
97 }
Zimuzoff991762019-02-01 19:25:44 +000098
Zimuzo9e57ecb2019-02-04 15:34:08 +000099 RollbackInfo rollback = rollbackPair.first;
100 // We only log mainline package rollbacks, so check if rollback contains the
101 // module metadata provider, if it does, the rollback is a mainline rollback
102 boolean hasModuleMetadataPackage = rollbackPair.second;
Zimuzo03eeb132019-01-30 15:13:56 +0000103
Zimuzo9e57ecb2019-02-04 15:34:08 +0000104 if (hasModuleMetadataPackage) {
105 StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
106 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
107 moduleMetadataPackage.getPackageName(),
108 moduleMetadataPackage.getVersionCode());
109 }
Zimuzoe5009cd2019-01-23 18:11:58 +0000110 LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
Zimuzo9e57ecb2019-02-04 15:34:08 +0000111 if (hasModuleMetadataPackage) {
112 int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
113 RollbackManager.STATUS_FAILURE);
114 if (status == RollbackManager.STATUS_SUCCESS) {
115 StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
116 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
117 moduleMetadataPackage.getPackageName(),
118 moduleMetadataPackage.getVersionCode());
Zimuzoff991762019-02-01 19:25:44 +0000119 if (rollback.isStaged()) {
120 int rollbackId = rollback.getRollbackId();
121 BroadcastReceiver listener =
122 listenForStagedSessionReady(rollbackManager, rollbackId);
123 handleStagedSessionChange(rollbackManager, rollbackId, listener);
124 }
Zimuzo9e57ecb2019-02-04 15:34:08 +0000125 } else {
126 StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
127 StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
128 moduleMetadataPackage.getPackageName(),
129 moduleMetadataPackage.getVersionCode());
130 }
Zimuzoe5009cd2019-01-23 18:11:58 +0000131 }
132 });
133
Zimuzoe5009cd2019-01-23 18:11:58 +0000134 mHandler.post(() ->
Zimuzoc1197802019-01-30 12:05:41 +0000135 rollbackManager.commitRollback(rollback.getRollbackId(),
Zimuzo9e57ecb2019-02-04 15:34:08 +0000136 Collections.singletonList(failedPackage),
Richard Uhlere87368e2019-01-24 16:34:14 +0000137 rollbackReceiver.getIntentSender()));
Zimuzoe5009cd2019-01-23 18:11:58 +0000138 // Assume rollback executed successfully
139 return true;
140 }
141
142 @Override
143 public String getName() {
144 return NAME;
Zimuzoc4073cc2019-01-18 18:39:18 +0000145 }
146
147 /**
148 * Start observing health of {@code packages} for {@code durationMs}.
149 * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
150 */
151 public void startObservingHealth(List<String> packages, long durationMs) {
152 PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
153 }
154
Zimuzo9e57ecb2019-02-04 15:34:08 +0000155 private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager,
Zimuzo71d931e2019-02-01 13:08:16 +0000156 VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) {
Zimuzoc1197802019-01-30 12:05:41 +0000157 for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
Zimuzo03eeb132019-01-30 15:13:56 +0000158 // We only rollback mainline packages, so check if rollback contains the
159 // module metadata provider, if it does, the rollback is a mainline rollback
160 boolean hasModuleMetadataPackage = false;
161 boolean hasFailedPackage = false;
Zimuzoe5009cd2019-01-23 18:11:58 +0000162 for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
Zimuzo03eeb132019-01-30 15:13:56 +0000163 hasModuleMetadataPackage |= packageRollback.getPackageName().equals(
Zimuzo71d931e2019-02-01 13:08:16 +0000164 moduleMetadataPackage.getPackageName());
165 hasFailedPackage |= packageRollback.getPackageName().equals(
166 failedPackage.getPackageName())
Zimuzo972e1cd2019-01-28 16:30:01 +0000167 && packageRollback.getVersionRolledBackFrom().getVersionCode()
Zimuzo71d931e2019-02-01 13:08:16 +0000168 == failedPackage.getVersionCode();
Zimuzo03eeb132019-01-30 15:13:56 +0000169 }
Zimuzo9e57ecb2019-02-04 15:34:08 +0000170 if (hasFailedPackage) {
171 return new Pair<RollbackInfo, Boolean>(rollback, hasModuleMetadataPackage);
Zimuzoe5009cd2019-01-23 18:11:58 +0000172 }
173 }
174 return null;
Zimuzoc4073cc2019-01-18 18:39:18 +0000175 }
Zimuzo03eeb132019-01-30 15:13:56 +0000176
177 private VersionedPackage getModuleMetadataPackage() {
178 String packageName = mContext.getResources().getString(
179 R.string.config_defaultModuleMetadataProvider);
Zimuzo9e57ecb2019-02-04 15:34:08 +0000180 if (TextUtils.isEmpty(packageName)) {
Zimuzo03eeb132019-01-30 15:13:56 +0000181 return null;
182 }
183
184 try {
185 return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
186 packageName, 0 /* flags */).getLongVersionCode());
187 } catch (PackageManager.NameNotFoundException e) {
188 Slog.w(TAG, "Module metadata provider not found");
189 return null;
190 }
191 }
Zimuzoff991762019-02-01 19:25:44 +0000192
193 private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
194 int rollbackId) {
195 BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
196 @Override
197 public void onReceive(Context context, Intent intent) {
198 handleStagedSessionChange(rollbackManager,
199 rollbackId, this /* BroadcastReceiver */);
200 }
201 };
202 IntentFilter sessionUpdatedFilter =
203 new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
204 mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
205 return sessionUpdatedReceiver;
206 }
207
208 private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
209 BroadcastReceiver listener) {
210 PackageInstaller packageInstaller =
211 mContext.getPackageManager().getPackageInstaller();
212 List<RollbackInfo> recentRollbacks =
213 rollbackManager.getRecentlyCommittedRollbacks();
214 for (int i = 0; i < recentRollbacks.size(); i++) {
215 RollbackInfo recentRollback = recentRollbacks.get(i);
216 int sessionId = recentRollback.getCommittedSessionId();
217 if ((rollbackId == recentRollback.getRollbackId())
218 && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
219 PackageInstaller.SessionInfo sessionInfo =
220 packageInstaller.getSessionInfo(sessionId);
Dario Freni60a96c12019-02-24 21:01:29 +0000221 if (sessionInfo.isStagedSessionReady()) {
Zimuzoff991762019-02-01 19:25:44 +0000222 mContext.unregisterReceiver(listener);
223 mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
Dario Freni60a96c12019-02-24 21:01:29 +0000224 } else if (sessionInfo.isStagedSessionFailed()) {
Zimuzoff991762019-02-01 19:25:44 +0000225 mContext.unregisterReceiver(listener);
226 }
227 }
228 }
229 }
Zimuzoc4073cc2019-01-18 18:39:18 +0000230}