summaryrefslogtreecommitdiff
path: root/core/java/android/os/DynamicAndroidManager.java
diff options
context:
space:
mode:
authorHoward Chen <howardsoc@google.com>2019-01-07 14:10:44 +0800
committerHoward Chen <howardsoc@google.com>2019-01-31 15:10:21 +0800
commitf17f42b0df9a5564d90f0b60555fc8956a5732bc (patch)
tree9dd33cec95875f6827ca9a82f59ff60f4a245a72 /core/java/android/os/DynamicAndroidManager.java
parent8b194fe9d8e113712d5005e6c1405734ed5b4996 (diff)
Add the DynamicAndroid Service
Define the DynamicAndroid with AIDL. Add a java implementation. Start a service instance in the system server. Add a permission test. Bug: 122015653 Test: Build & Test on a pixel phone with following command \ ./frameworks/base/services/tests/runtests.py -e class com.android.server.DynamicAndroidTest Merged-In: I2e54b6b71fac4a4c5a9c9c25ce6bdac74cddcfb7 Change-Id: I2e54b6b71fac4a4c5a9c9c25ce6bdac74cddcfb7
Diffstat (limited to 'core/java/android/os/DynamicAndroidManager.java')
-rw-r--r--core/java/android/os/DynamicAndroidManager.java188
1 files changed, 188 insertions, 0 deletions
diff --git a/core/java/android/os/DynamicAndroidManager.java b/core/java/android/os/DynamicAndroidManager.java
new file mode 100644
index 000000000000..5238896016ee
--- /dev/null
+++ b/core/java/android/os/DynamicAndroidManager.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 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.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.gsi.GsiProgress;
+
+/**
+ * The DynamicAndroidManager offers a mechanism to use a new Android image temporarily. After the
+ * installation, the device can reboot into this image with a new created /data. This image will
+ * last until the next reboot and then the device will go back to the original image. However the
+ * installed image and the new created /data are not deleted but disabled. Thus the application can
+ * either re-enable the installed image by calling {@link #toggle} or use the {@link #remove} to
+ * delete it completely. In other words, there are three device states: no installation, installed
+ * and running. The procedure to install a DynamicAndroid starts with a {@link #startInstallation},
+ * followed by a series of {@link #write} and ends with a {@link commit}. Once the installation is
+ * complete, the device state changes from no installation to the installed state and a followed
+ * reboot will change its state to running. Note one instance of dynamic android can exist on a
+ * given device thus the {@link #startInstallation} will fail if the device is currently running a
+ * DynamicAndroid.
+ *
+ * @hide
+ */
+@SystemService(Context.DYNAMIC_ANDROID_SERVICE)
+public class DynamicAndroidManager {
+ private static final String TAG = "DynamicAndroidManager";
+
+ private final IDynamicAndroidService mService;
+
+ /** {@hide} */
+ public DynamicAndroidManager(IDynamicAndroidService service) {
+ mService = service;
+ }
+
+ /** The DynamicAndroidManager.Session represents a started session for the installation. */
+ public class Session {
+ private Session() {}
+ /**
+ * Write a chunk of the DynamicAndroid system image
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
+ * error.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean write(byte[] buf) {
+ try {
+ return mService.write(buf);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Finish write and make device to boot into the it after reboot.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
+ * error.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean commit() {
+ try {
+ return mService.commit();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+ /**
+ * Start DynamicAndroid installation. This call may take an unbounded amount of time. The caller
+ * may use another thread to call the getStartProgress() to get the progress.
+ *
+ * @param systemSize system size in bytes
+ * @param userdataSize userdata size in bytes
+ * @return {@code true} if the call succeeds. {@code false} either the device does not contain
+ * enough space or a DynamicAndroid is currently in use where the {@link #isInUse} would be
+ * true.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public Session startInstallation(long systemSize, long userdataSize) {
+ try {
+ if (mService.startInstallation(systemSize, userdataSize)) {
+ return new Session();
+ } else {
+ return null;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Query the progress of the current installation operation. This can be called while the
+ * installation is in progress.
+ *
+ * @return GsiProgress GsiProgress { int status; long bytes_processed; long total_bytes; } The
+ * status field can be IGsiService.STATUS_NO_OPERATION, IGsiService.STATUS_WORKING or
+ * IGsiService.STATUS_COMPLETE.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public GsiProgress getInstallationProgress() {
+ try {
+ return mService.getInstallationProgress();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Abort the installation process. Note this method must be called in a thread other than the
+ * one calling the startInstallation method as the startInstallation method will not return
+ * until it is finished.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installation
+ * currently.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean abort() {
+ try {
+ return mService.abort();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /** @return {@code true} if the device is running a dynamic android */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean isInUse() {
+ try {
+ return mService.isInUse();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /** @return {@code true} if the device has a dynamic android installed */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean isInstalled() {
+ try {
+ return mService.isInstalled();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Remove DynamicAndroid installation if present
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean remove() {
+ try {
+ return mService.remove();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Enable DynamicAndroid when it's not enabled, otherwise, disable it.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean toggle() {
+ try {
+ return mService.toggle();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}