Merge "Support multiple DSU installations"
This commit is contained in:
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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)) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
sVerifiedUrl = url.toString();
|
if (url != null) {
|
||||||
|
sVerifiedUrl = url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
// start service
|
// start service
|
||||||
Intent intent = new Intent(this, DynamicSystemInstallationService.class);
|
Intent intent = new Intent(this, DynamicSystemInstallationService.class);
|
||||||
intent.setData(url);
|
if (url != null) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user