Merge "Support multiple DSU installations"

This commit is contained in:
Howard Chen
2020-01-16 05:33:10 +00:00
committed by Gerrit Code Review
7 changed files with 50 additions and 22 deletions

View File

@@ -106,9 +106,9 @@ public class DynamicSystemManager {
* @return true if the call succeeds * @return true if the call succeeds
*/ */
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
public boolean startInstallation() { public boolean startInstallation(String dsuSlot) {
try { try {
return mService.startInstallation(); return mService.startInstallation(dsuSlot);
} catch (RemoteException e) { } catch (RemoteException e) {
throw new RuntimeException(e.toString()); throw new RuntimeException(e.toString());
} }

View File

@@ -22,9 +22,10 @@ interface IDynamicSystemService
{ {
/** /**
* Start DynamicSystem installation. * Start DynamicSystem installation.
* @param dsuSlot Name used to identify this installation
* @return true if the call succeeds * @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 * Create a DSU partition. This call may take 60~90 seconds. The caller

View File

@@ -56,6 +56,7 @@ import android.os.PowerManager;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.image.DynamicSystemClient; import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager; import android.os.image.DynamicSystemManager;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
@@ -74,6 +75,8 @@ public class DynamicSystemInstallationService extends Service
// TODO (b/131866826): This is currently for test only. Will move this to System API. // 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_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 * Intent actions
@@ -244,10 +247,15 @@ public class DynamicSystemInstallationService extends Service
long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0); long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0); long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false); 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 // TODO: better constructor or builder
mInstallTask = new InstallationAsyncTask( mInstallTask =
url, systemSize, userdataSize, this, mDynSystem, this); new InstallationAsyncTask(
url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this);
mInstallTask.execute(); mInstallTask.execute();

View File

@@ -89,10 +89,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
interface ProgressListener { interface ProgressListener {
void onProgressUpdate(Progress progress); void onProgressUpdate(Progress progress);
void onResult(int resultCode, Throwable detail); void onResult(int resultCode, Throwable detail);
} }
private final String mUrl; private final String mUrl;
private final String mDsuSlot;
private final long mSystemSize; private final long mSystemSize;
private final long mUserdataSize; private final long mUserdataSize;
private final Context mContext; private final Context mContext;
@@ -106,9 +108,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
private InputStream mStream; private InputStream mStream;
private ZipFile mZipFile; private ZipFile mZipFile;
InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context, InstallationAsyncTask(
DynamicSystemManager dynSystem, ProgressListener listener) { String url,
String dsuSlot,
long systemSize,
long userdataSize,
Context context,
DynamicSystemManager dynSystem,
ProgressListener listener) {
mUrl = url; mUrl = url;
mDsuSlot = dsuSlot;
mSystemSize = systemSize; mSystemSize = systemSize;
mUserdataSize = userdataSize; mUserdataSize = userdataSize;
mContext = context; mContext = context;
@@ -126,14 +135,17 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
verifyAndPrepare(); verifyAndPrepare();
mDynSystem.startInstallation(); mDynSystem.startInstallation(mDsuSlot);
installUserdata(); installUserdata();
if (isCancelled()) { if (isCancelled()) {
mDynSystem.remove(); mDynSystem.remove();
return null; return null;
} }
if (mUrl == null) {
mDynSystem.finishInstallation();
return null;
}
installImages(); installImages();
if (isCancelled()) { if (isCancelled()) {
mDynSystem.remove(); mDynSystem.remove();
@@ -194,6 +206,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
} }
private void verifyAndPrepare() throws Exception { private void verifyAndPrepare() throws Exception {
if (mUrl == null) {
return;
}
String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1); String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1);
if ("gz".equals(extension) || "gzip".equals(extension)) { if ("gz".equals(extension) || "gzip".equals(extension)) {

View File

@@ -28,11 +28,9 @@ import android.os.image.DynamicSystemClient;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
import android.util.Log; import android.util.Log;
/** /**
* This Activity starts KeyguardManager and ask the user to confirm * This Activity starts KeyguardManager and ask the user to confirm before any installation request.
* before any installation request. If the device is not protected by * If the device is not protected by a password, it approves the request by default.
* a password, it approves the request by default.
*/ */
public class VerificationActivity extends Activity { public class VerificationActivity extends Activity {
@@ -88,11 +86,15 @@ public class VerificationActivity extends Activity {
Uri url = callingIntent.getData(); Uri url = callingIntent.getData();
Bundle extras = callingIntent.getExtras(); Bundle extras = callingIntent.getExtras();
if (url != null) {
sVerifiedUrl = url.toString(); sVerifiedUrl = url.toString();
}
// start service // start service
Intent intent = new Intent(this, DynamicSystemInstallationService.class); Intent intent = new Intent(this, DynamicSystemInstallationService.class);
if (url != null) {
intent.setData(url); intent.setData(url);
}
intent.setAction(DynamicSystemClient.ACTION_START_INSTALL); intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
intent.putExtras(extras); intent.putExtras(extras);
@@ -106,6 +108,7 @@ public class VerificationActivity extends Activity {
} }
static boolean isVerified(String url) { static boolean isVerified(String url) {
if (url == null) return true;
return sVerifiedUrl != null && sVerifiedUrl.equals(url); return sVerifiedUrl != null && sVerifiedUrl.equals(url);
} }
} }

View File

@@ -44,9 +44,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
private static final String TAG = "DynamicSystemService"; private static final String TAG = "DynamicSystemService";
private static final String NO_SERVICE_ERROR = "no gsiservice"; private static final String NO_SERVICE_ERROR = "no gsiservice";
private static final int GSID_ROUGH_TIMEOUT_MS = 8192; 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 Context mContext;
private String mInstallPath; private String mInstallPath, mDsuSlot;
private volatile IGsiService mGsiService; private volatile IGsiService mGsiService;
DynamicSystemService(Context context) { DynamicSystemService(Context context) {
@@ -115,7 +115,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
} }
@Override @Override
public boolean startInstallation() throws RemoteException { public boolean startInstallation(String dsuSlot) throws RemoteException {
IGsiService service = getGsiService(); IGsiService service = getGsiService();
// priority from high to low: sysprop -> sdcard -> /data // priority from high to low: sysprop -> sdcard -> /data
String path = SystemProperties.get("os.aot.path"); String path = SystemProperties.get("os.aot.path");
@@ -129,16 +129,17 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue; if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue;
File sdCard = volume.getPathFile(); File sdCard = volume.getPathFile();
if (sdCard.isDirectory()) { if (sdCard.isDirectory()) {
path = sdCard.getPath(); path = new File(sdCard, dsuSlot).getPath();
break; break;
} }
} }
if (path.isEmpty()) { if (path.isEmpty()) {
path = PATH_DEFAULT; path = PATH_DEFAULT + dsuSlot;
} }
Slog.i(TAG, "startInstallation -> " + path); Slog.i(TAG, "startInstallation -> " + path);
} }
mInstallPath = path; mInstallPath = path;
mDsuSlot = dsuSlot;
if (service.openInstall(path) != 0) { if (service.openInstall(path) != 0) {
Slog.i(TAG, "Failed to open " + path); Slog.i(TAG, "Failed to open " + path);
return false; return false;
@@ -203,7 +204,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements
public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException { public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
IGsiService gsiService = getGsiService(); IGsiService gsiService = getGsiService();
if (enable) { if (enable) {
return gsiService.enableGsi(oneShot) == 0; return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
} else { } else {
return gsiService.disableGsi(); return gsiService.disableGsi();
} }

View File

@@ -36,7 +36,7 @@ public class DynamicSystemServiceTest extends AndroidTestCase {
public void test1() { public void test1() {
assertTrue("dynamic_system service available", mService != null); assertTrue("dynamic_system service available", mService != null);
try { try {
mService.startInstallation(); mService.startInstallation("dsu");
fail("DynamicSystemService did not throw SecurityException as expected"); fail("DynamicSystemService did not throw SecurityException as expected");
} catch (SecurityException e) { } catch (SecurityException e) {
// expected // expected