Support multiple DSU installations
Bug: 144247097
Test: adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity \
-a android.os.image.action.START_INSTALL \
-d file:///storage/emulated/0/Download/system.raw.gz \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1) \
--el KEY_USERDATA_SIZE 8589934592
Change-Id: Ib2f86039c4c0c1dae2bc94a702721572567bcbf2
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 4c92c28..cbf531c 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -106,9 +106,9 @@
* @return true if the call succeeds
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
- public boolean startInstallation() {
+ public boolean startInstallation(String dsuSlot) {
try {
- return mService.startInstallation();
+ return mService.startInstallation(dsuSlot);
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index 69cbab2..cc32f99 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -22,9 +22,10 @@
{
/**
* Start DynamicSystem installation.
+ * @param dsuSlot Name used to identify this installation
* @return true if the call succeeds
*/
- boolean startInstallation();
+ boolean startInstallation(@utf8InCpp String dsuSlot);
/**
* Create a DSU partition. This call may take 60~90 seconds. The caller
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 9e49826..56540f0 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -56,6 +56,7 @@
import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager;
+import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -74,6 +75,8 @@
// TODO (b/131866826): This is currently for test only. Will move this to System API.
static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
+ static final String KEY_DSU_SLOT = "KEY_DSU_SLOT";
+ static final String DEFAULT_DSU_SLOT = "dsu";
/*
* Intent actions
@@ -244,10 +247,15 @@
long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
+ String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT);
+ if (TextUtils.isEmpty(dsuSlot)) {
+ dsuSlot = DEFAULT_DSU_SLOT;
+ }
// TODO: better constructor or builder
- mInstallTask = new InstallationAsyncTask(
- url, systemSize, userdataSize, this, mDynSystem, this);
+ mInstallTask =
+ new InstallationAsyncTask(
+ url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this);
mInstallTask.execute();
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index b206a1f..9aea0e7 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -89,10 +89,12 @@
interface ProgressListener {
void onProgressUpdate(Progress progress);
+
void onResult(int resultCode, Throwable detail);
}
private final String mUrl;
+ private final String mDsuSlot;
private final long mSystemSize;
private final long mUserdataSize;
private final Context mContext;
@@ -106,9 +108,16 @@
private InputStream mStream;
private ZipFile mZipFile;
- InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context,
- DynamicSystemManager dynSystem, ProgressListener listener) {
+ InstallationAsyncTask(
+ String url,
+ String dsuSlot,
+ long systemSize,
+ long userdataSize,
+ Context context,
+ DynamicSystemManager dynSystem,
+ ProgressListener listener) {
mUrl = url;
+ mDsuSlot = dsuSlot;
mSystemSize = systemSize;
mUserdataSize = userdataSize;
mContext = context;
@@ -126,14 +135,17 @@
verifyAndPrepare();
- mDynSystem.startInstallation();
+ mDynSystem.startInstallation(mDsuSlot);
installUserdata();
if (isCancelled()) {
mDynSystem.remove();
return null;
}
-
+ if (mUrl == null) {
+ mDynSystem.finishInstallation();
+ return null;
+ }
installImages();
if (isCancelled()) {
mDynSystem.remove();
@@ -194,6 +206,9 @@
}
private void verifyAndPrepare() throws Exception {
+ if (mUrl == null) {
+ return;
+ }
String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1);
if ("gz".equals(extension) || "gzip".equals(extension)) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index 3b3933b..e42ded7 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -28,11 +28,9 @@
import android.util.FeatureFlagUtils;
import android.util.Log;
-
/**
- * This Activity starts KeyguardManager and ask the user to confirm
- * before any installation request. If the device is not protected by
- * a password, it approves the request by default.
+ * This Activity starts KeyguardManager and ask the user to confirm before any installation request.
+ * If the device is not protected by a password, it approves the request by default.
*/
public class VerificationActivity extends Activity {
@@ -88,11 +86,15 @@
Uri url = callingIntent.getData();
Bundle extras = callingIntent.getExtras();
- sVerifiedUrl = url.toString();
+ if (url != null) {
+ sVerifiedUrl = url.toString();
+ }
// start service
Intent intent = new Intent(this, DynamicSystemInstallationService.class);
- intent.setData(url);
+ if (url != null) {
+ intent.setData(url);
+ }
intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
intent.putExtras(extras);
@@ -106,6 +108,7 @@
}
static boolean isVerified(String url) {
+ if (url == null) return true;
return sVerifiedUrl != null && sVerifiedUrl.equals(url);
}
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 7909e30..c60460f 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -44,9 +44,9 @@
private static final String TAG = "DynamicSystemService";
private static final String NO_SERVICE_ERROR = "no gsiservice";
private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
- private static final String PATH_DEFAULT = "/data/gsi";
+ private static final String PATH_DEFAULT = "/data/gsi/";
private Context mContext;
- private String mInstallPath;
+ private String mInstallPath, mDsuSlot;
private volatile IGsiService mGsiService;
DynamicSystemService(Context context) {
@@ -115,7 +115,7 @@
}
@Override
- public boolean startInstallation() throws RemoteException {
+ public boolean startInstallation(String dsuSlot) throws RemoteException {
IGsiService service = getGsiService();
// priority from high to low: sysprop -> sdcard -> /data
String path = SystemProperties.get("os.aot.path");
@@ -129,16 +129,17 @@
if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue;
File sdCard = volume.getPathFile();
if (sdCard.isDirectory()) {
- path = sdCard.getPath();
+ path = new File(sdCard, dsuSlot).getPath();
break;
}
}
if (path.isEmpty()) {
- path = PATH_DEFAULT;
+ path = PATH_DEFAULT + dsuSlot;
}
Slog.i(TAG, "startInstallation -> " + path);
}
mInstallPath = path;
+ mDsuSlot = dsuSlot;
if (service.openInstall(path) != 0) {
Slog.i(TAG, "Failed to open " + path);
return false;
@@ -203,7 +204,7 @@
public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
IGsiService gsiService = getGsiService();
if (enable) {
- return gsiService.enableGsi(oneShot) == 0;
+ return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
} else {
return gsiService.disableGsi();
}
diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index 50437b4..d367f71 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -36,7 +36,7 @@
public void test1() {
assertTrue("dynamic_system service available", mService != null);
try {
- mService.startInstallation();
+ mService.startInstallation("dsu");
fail("DynamicSystemService did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected