summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tao Bao <tbao@google.com> 2017-01-24 15:08:21 -0800
committer Tao Bao <tbao@google.com> 2018-01-18 14:41:41 -0800
commit07342dc1755706d26e614e18fa5ab3b32c435d38 (patch)
tree6f4f58ea7f3d24821d91d6eae9cee7b67c13288f
parent022320cb57c39bddab00fda7b8e14840ad503e23 (diff)
Add pending system update info system APIs.
This CL adds system APIs in android.os.SystemUpdateManager. The APIs allow system updater apps (RECOVERY permission required) to publish the pending system update information, and allow other apps to query the info accordingly (requiring RECOVERY or READ_SYSTEM_UPDATE_INFO permission). Design doc in go/pi-ota-platform-api. Bug: 67437079 Test: Use test apps to call the new APIs to query and set the update info respectively. Change-Id: Id54b4a48d02922d2abd906dd7e2ec80a656fc9b1
-rw-r--r--Android.bp1
-rw-r--r--api/system-current.txt18
-rw-r--r--core/java/android/app/SystemServiceRegistry.java13
-rw-r--r--core/java/android/content/Context.java14
-rw-r--r--core/java/android/os/ISystemUpdateManager.aidl27
-rw-r--r--core/java/android/os/SystemUpdateManager.java152
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--services/core/java/com/android/server/SystemUpdateManagerService.java255
-rw-r--r--services/java/com/android/server/SystemServer.java9
9 files changed, 493 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp
index defe655e5fd9..74f19e1d68da 100644
--- a/Android.bp
+++ b/Android.bp
@@ -230,6 +230,7 @@ java_library {
"core/java/android/os/ISchedulingPolicyService.aidl",
"core/java/android/os/IStatsCompanionService.aidl",
"core/java/android/os/IStatsManager.aidl",
+ "core/java/android/os/ISystemUpdateManager.aidl",
"core/java/android/os/IThermalEventListener.aidl",
"core/java/android/os/IThermalService.aidl",
"core/java/android/os/IUpdateLock.aidl",
diff --git a/api/system-current.txt b/api/system-current.txt
index ca5f66e90d29..a520ed613faa 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -131,6 +131,7 @@ package android {
field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
+ field public static final java.lang.String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
@@ -760,6 +761,7 @@ package android.content {
field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
field public static final java.lang.String STATS_MANAGER = "stats";
+ field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
field public static final java.lang.String VR_SERVICE = "vrmanager";
field public static final java.lang.String WIFI_RTT_SERVICE = "rttmanager";
field public static final java.lang.String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -3487,6 +3489,22 @@ package android.os {
method public abstract void onResult(android.os.Bundle);
}
+ public class SystemUpdateManager {
+ method public android.os.Bundle retrieveSystemUpdateInfo();
+ method public void updateSystemUpdateInfo(android.os.PersistableBundle);
+ field public static final java.lang.String KEY_IS_SECURITY_UPDATE = "is_security_update";
+ field public static final java.lang.String KEY_STATUS = "status";
+ field public static final java.lang.String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
+ field public static final java.lang.String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
+ field public static final java.lang.String KEY_TITLE = "title";
+ field public static final int STATUS_IDLE = 1; // 0x1
+ field public static final int STATUS_IN_PROGRESS = 3; // 0x3
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ field public static final int STATUS_WAITING_DOWNLOAD = 2; // 0x2
+ field public static final int STATUS_WAITING_INSTALL = 4; // 0x4
+ field public static final int STATUS_WAITING_REBOOT = 5; // 0x5
+ }
+
public class UpdateEngine {
ctor public UpdateEngine();
method public void applyPayload(java.lang.String, long, long, java.lang.String[]);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6eafcc437447..b5662cbf8300 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -112,6 +112,7 @@ import android.os.IBinder;
import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
+import android.os.ISystemUpdateManager;
import android.os.IUserManager;
import android.os.IncidentManager;
import android.os.PowerManager;
@@ -119,6 +120,7 @@ import android.os.Process;
import android.os.RecoverySystem;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemUpdateManager;
import android.os.SystemVibrator;
import android.os.UserHandle;
import android.os.UserManager;
@@ -485,6 +487,17 @@ final class SystemServiceRegistry {
return new StorageStatsManager(ctx, service);
}});
+ registerService(Context.SYSTEM_UPDATE_SERVICE, SystemUpdateManager.class,
+ new CachedServiceFetcher<SystemUpdateManager>() {
+ @Override
+ public SystemUpdateManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.SYSTEM_UPDATE_SERVICE);
+ ISystemUpdateManager service = ISystemUpdateManager.Stub.asInterface(b);
+ return new SystemUpdateManager(service);
+ }});
+
registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
new CachedServiceFetcher<TelephonyManager>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f69e76445aa7..e374bbc1c017 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3024,7 +3024,8 @@ public abstract class Context {
//@hide: INCIDENT_SERVICE,
//@hide: STATS_COMPANION_SERVICE,
COMPANION_DEVICE_SERVICE,
- CROSS_PROFILE_APPS_SERVICE
+ CROSS_PROFILE_APPS_SERVICE,
+ //@hide: SYSTEM_UPDATE_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3242,6 +3243,17 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.os.SystemUpdateManager} for accessing the system update
+ * manager service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ @SystemApi
+ public static final String SYSTEM_UPDATE_SERVICE = "system_update";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.view.WindowManager} for accessing the system's window
* manager.
*
diff --git a/core/java/android/os/ISystemUpdateManager.aidl b/core/java/android/os/ISystemUpdateManager.aidl
new file mode 100644
index 000000000000..f7f50791f528
--- /dev/null
+++ b/core/java/android/os/ISystemUpdateManager.aidl
@@ -0,0 +1,27 @@
+/* //device/java/android/android/os/ISystemUpdateInfo.aidl
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+/** @hide */
+interface ISystemUpdateManager {
+ Bundle retrieveSystemUpdateInfo();
+ void updateSystemUpdateInfo(in PersistableBundle data);
+}
diff --git a/core/java/android/os/SystemUpdateManager.java b/core/java/android/os/SystemUpdateManager.java
new file mode 100644
index 000000000000..ce3e225975f0
--- /dev/null
+++ b/core/java/android/os/SystemUpdateManager.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * Allows querying and posting system update information.
+ *
+ * {@hide}
+ */
+@SystemApi
+@SystemService(Context.SYSTEM_UPDATE_SERVICE)
+public class SystemUpdateManager {
+ private static final String TAG = "SystemUpdateManager";
+
+ /** The status key of the system update info, expecting an int value. */
+ @SystemApi
+ public static final String KEY_STATUS = "status";
+
+ /** The title of the current update, expecting a String value. */
+ @SystemApi
+ public static final String KEY_TITLE = "title";
+
+ /** Whether it is a security update, expecting a boolean value. */
+ @SystemApi
+ public static final String KEY_IS_SECURITY_UPDATE = "is_security_update";
+
+ /** The build fingerprint after installing the current update, expecting a String value. */
+ @SystemApi
+ public static final String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
+
+ /** The security patch level after installing the current update, expecting a String value. */
+ @SystemApi
+ public static final String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
+
+ /**
+ * The KEY_STATUS value that indicates there's no update status info available.
+ */
+ @SystemApi
+ public static final int STATUS_UNKNOWN = 0;
+
+ /**
+ * The KEY_STATUS value that indicates there's no pending update.
+ */
+ @SystemApi
+ public static final int STATUS_IDLE = 1;
+
+ /**
+ * The KEY_STATUS value that indicates an update is available for download, but pending user
+ * approval to start.
+ */
+ @SystemApi
+ public static final int STATUS_WAITING_DOWNLOAD = 2;
+
+ /**
+ * The KEY_STATUS value that indicates an update is in progress (i.e. downloading or installing
+ * has started).
+ */
+ @SystemApi
+ public static final int STATUS_IN_PROGRESS = 3;
+
+ /**
+ * The KEY_STATUS value that indicates an update is available for install.
+ */
+ @SystemApi
+ public static final int STATUS_WAITING_INSTALL = 4;
+
+ /**
+ * The KEY_STATUS value that indicates an update will be installed after a reboot. This applies
+ * to both of A/B and non-A/B OTAs.
+ */
+ @SystemApi
+ public static final int STATUS_WAITING_REBOOT = 5;
+
+ private final ISystemUpdateManager mService;
+
+ /** @hide */
+ public SystemUpdateManager(ISystemUpdateManager service) {
+ mService = checkNotNull(service, "missing ISystemUpdateManager");
+ }
+
+ /**
+ * Queries the current pending system update info.
+ *
+ * <p>Requires the {@link android.Manifest.permission#READ_SYSTEM_UPDATE_INFO} or
+ * {@link android.Manifest.permission#RECOVERY} permission.
+ *
+ * @return A {@code Bundle} that contains the pending system update information in key-value
+ * pairs.
+ *
+ * @throws SecurityException if the caller is not allowed to read the info.
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_SYSTEM_UPDATE_INFO,
+ android.Manifest.permission.RECOVERY,
+ })
+ public Bundle retrieveSystemUpdateInfo() {
+ try {
+ return mService.retrieveSystemUpdateInfo();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allows a system updater to publish the pending update info.
+ *
+ * <p>The reported info will not persist across reboots. Because only the reporting updater
+ * understands the criteria to determine a successful/failed update.
+ *
+ * <p>Requires the {@link android.Manifest.permission#RECOVERY} permission.
+ *
+ * @param infoBundle The {@code PersistableBundle} that contains the system update information,
+ * such as the current update status. {@link #KEY_STATUS} is required in the bundle.
+ *
+ * @throws IllegalArgumentException if @link #KEY_STATUS} does not exist.
+ * @throws SecurityException if the caller is not allowed to update the info.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.RECOVERY)
+ public void updateSystemUpdateInfo(PersistableBundle infoBundle) {
+ if (infoBundle == null || !infoBundle.containsKey(KEY_STATUS)) {
+ throw new IllegalArgumentException("Missing status in the bundle");
+ }
+ try {
+ mService.updateSystemUpdateInfo(infoBundle);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d2a22d0794b6..cfd7c958a181 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2309,6 +2309,11 @@
<permission android:name="android.permission.RECOVERY"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to read system update info.
+ @hide -->
+ <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
+ android:protectionLevel="signature" />
+
<!-- Allows the system to bind to an application's task services
@hide -->
<permission android:name="android.permission.BIND_JOB_SERVICE"
diff --git a/services/core/java/com/android/server/SystemUpdateManagerService.java b/services/core/java/com/android/server/SystemUpdateManagerService.java
new file mode 100644
index 000000000000..6c1ffdd32d18
--- /dev/null
+++ b/services/core/java/com/android/server/SystemUpdateManagerService.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.os.SystemUpdateManager.KEY_STATUS;
+import static android.os.SystemUpdateManager.STATUS_IDLE;
+import static android.os.SystemUpdateManager.STATUS_UNKNOWN;
+
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ISystemUpdateManager;
+import android.os.PersistableBundle;
+import android.os.SystemUpdateManager;
+import android.provider.Settings;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class SystemUpdateManagerService extends ISystemUpdateManager.Stub {
+
+ private static final String TAG = "SystemUpdateManagerService";
+
+ private static final int UID_UNKNOWN = -1;
+
+ private static final String INFO_FILE = "system-update-info.xml";
+ private static final int INFO_FILE_VERSION = 0;
+ private static final String TAG_INFO = "info";
+ private static final String KEY_VERSION = "version";
+ private static final String KEY_UID = "uid";
+ private static final String KEY_BOOT_COUNT = "boot-count";
+ private static final String KEY_INFO_BUNDLE = "info-bundle";
+
+ private final Context mContext;
+ private final AtomicFile mFile;
+ private final Object mLock = new Object();
+ private int mLastUid = UID_UNKNOWN;
+ private int mLastStatus = STATUS_UNKNOWN;
+
+ public SystemUpdateManagerService(Context context) {
+ mContext = context;
+ mFile = new AtomicFile(new File(Environment.getDataSystemDirectory(), INFO_FILE));
+
+ // Populate mLastUid and mLastStatus.
+ synchronized (mLock) {
+ loadSystemUpdateInfoLocked();
+ }
+ }
+
+ @Override
+ public void updateSystemUpdateInfo(PersistableBundle infoBundle) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.RECOVERY, TAG);
+
+ int status = infoBundle.getInt(KEY_STATUS, STATUS_UNKNOWN);
+ if (status == STATUS_UNKNOWN) {
+ Slog.w(TAG, "Invalid status info. Ignored");
+ return;
+ }
+
+ // There could be multiple updater apps running on a device. But only one at most should
+ // be active (i.e. with a pending update), with the rest reporting idle status. We will
+ // only accept the reported status if any of the following conditions holds:
+ // a) none has been reported before;
+ // b) the current on-file status was last reported by the same caller;
+ // c) an active update is being reported.
+ int uid = Binder.getCallingUid();
+ if (mLastUid == UID_UNKNOWN || mLastUid == uid || status != STATUS_IDLE) {
+ synchronized (mLock) {
+ saveSystemUpdateInfoLocked(infoBundle, uid);
+ }
+ } else {
+ Slog.i(TAG, "Inactive updater reporting IDLE status. Ignored");
+ }
+ }
+
+ @Override
+ public Bundle retrieveSystemUpdateInfo() {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_SYSTEM_UPDATE_INFO)
+ == PackageManager.PERMISSION_DENIED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.RECOVERY)
+ == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException("Can't read system update info. Requiring "
+ + "READ_SYSTEM_UPDATE_INFO or RECOVERY permission.");
+ }
+
+ synchronized (mLock) {
+ return loadSystemUpdateInfoLocked();
+ }
+ }
+
+ // Reads and validates the info file. Returns the loaded info bundle on success; or a default
+ // info bundle with UNKNOWN status.
+ private Bundle loadSystemUpdateInfoLocked() {
+ PersistableBundle loadedBundle = null;
+ try (FileInputStream fis = mFile.openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, StandardCharsets.UTF_8.name());
+ loadedBundle = readInfoFileLocked(parser);
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "No existing info file " + mFile.getBaseFile());
+ } catch (XmlPullParserException e) {
+ Slog.e(TAG, "Failed to parse the info file:", e);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read the info file:", e);
+ }
+
+ // Validate the loaded bundle.
+ if (loadedBundle == null) {
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ int version = loadedBundle.getInt(KEY_VERSION, -1);
+ if (version == -1) {
+ Slog.w(TAG, "Invalid info file (invalid version). Ignored");
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ int lastUid = loadedBundle.getInt(KEY_UID, -1);
+ if (lastUid == -1) {
+ Slog.w(TAG, "Invalid info file (invalid UID). Ignored");
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ int lastBootCount = loadedBundle.getInt(KEY_BOOT_COUNT, -1);
+ if (lastBootCount == -1 || lastBootCount != getBootCount()) {
+ Slog.w(TAG, "Outdated info file. Ignored");
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ PersistableBundle infoBundle = loadedBundle.getPersistableBundle(KEY_INFO_BUNDLE);
+ if (infoBundle == null) {
+ Slog.w(TAG, "Invalid info file (missing info). Ignored");
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ int lastStatus = infoBundle.getInt(KEY_STATUS, STATUS_UNKNOWN);
+ if (lastStatus == STATUS_UNKNOWN) {
+ Slog.w(TAG, "Invalid info file (invalid status). Ignored");
+ return removeInfoFileAndGetDefaultInfoBundleLocked();
+ }
+
+ // Everything looks good upon reaching this point.
+ mLastStatus = lastStatus;
+ mLastUid = lastUid;
+ return new Bundle(infoBundle);
+ }
+
+ private void saveSystemUpdateInfoLocked(PersistableBundle infoBundle, int uid) {
+ // Wrap the incoming bundle with extra info (e.g. version, uid, boot count). We use nested
+ // PersistableBundle to avoid manually parsing XML attributes when loading the info back.
+ PersistableBundle outBundle = new PersistableBundle();
+ outBundle.putPersistableBundle(KEY_INFO_BUNDLE, infoBundle);
+ outBundle.putInt(KEY_VERSION, INFO_FILE_VERSION);
+ outBundle.putInt(KEY_UID, uid);
+ outBundle.putInt(KEY_BOOT_COUNT, getBootCount());
+
+ // Only update the info on success.
+ if (writeInfoFileLocked(outBundle)) {
+ mLastUid = uid;
+ mLastStatus = infoBundle.getInt(KEY_STATUS);
+ }
+ }
+
+ // Performs I/O work only, without validating the loaded info.
+ @Nullable
+ private PersistableBundle readInfoFileLocked(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != END_DOCUMENT) {
+ if (type == START_TAG && TAG_INFO.equals(parser.getName())) {
+ return PersistableBundle.restoreFromXml(parser);
+ }
+ }
+ return null;
+ }
+
+ private boolean writeInfoFileLocked(PersistableBundle outBundle) {
+ FileOutputStream fos = null;
+ try {
+ fos = mFile.startWrite();
+
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+
+ out.startTag(null, TAG_INFO);
+ outBundle.saveToXml(out);
+ out.endTag(null, TAG_INFO);
+
+ out.endDocument();
+ mFile.finishWrite(fos);
+ return true;
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "Failed to save the info file:", e);
+ if (fos != null) {
+ mFile.failWrite(fos);
+ }
+ }
+ return false;
+ }
+
+ private Bundle removeInfoFileAndGetDefaultInfoBundleLocked() {
+ if (mFile.exists()) {
+ Slog.i(TAG, "Removing info file");
+ mFile.delete();
+ }
+
+ mLastStatus = STATUS_UNKNOWN;
+ mLastUid = UID_UNKNOWN;
+ Bundle infoBundle = new Bundle();
+ infoBundle.putInt(KEY_STATUS, STATUS_UNKNOWN);
+ return infoBundle;
+ }
+
+ private int getBootCount() {
+ return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT, 0);
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3199bfa49455..8198a186519e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1172,6 +1172,15 @@ public final class SystemServer {
}
traceEnd();
+ traceBeginAndSlog("StartSystemUpdateManagerService");
+ try {
+ ServiceManager.addService(Context.SYSTEM_UPDATE_SERVICE,
+ new SystemUpdateManagerService(context));
+ } catch (Throwable e) {
+ reportWtf("starting SystemUpdateManagerService", e);
+ }
+ traceEnd();
+
traceBeginAndSlog("StartUpdateLockService");
try {
ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,