Merge "[pm/incremental] disable unstartable state and hide related APIs"
This commit is contained in:
@@ -10683,8 +10683,6 @@ package android.content {
|
||||
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
|
||||
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
|
||||
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
|
||||
field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
|
||||
field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
|
||||
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
|
||||
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
|
||||
field public static final String ACTION_PICK = "android.intent.action.PICK";
|
||||
@@ -12312,9 +12310,6 @@ package android.content.pm {
|
||||
field public static final int SYNCHRONOUS = 2; // 0x2
|
||||
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
|
||||
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
|
||||
field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
|
||||
field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
|
||||
field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
|
||||
field public static final int VERIFICATION_ALLOW = 1; // 0x1
|
||||
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
|
||||
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
|
||||
|
||||
@@ -10683,8 +10683,6 @@ package android.content {
|
||||
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
|
||||
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
|
||||
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
|
||||
field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
|
||||
field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
|
||||
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
|
||||
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
|
||||
field public static final String ACTION_PICK = "android.intent.action.PICK";
|
||||
@@ -12312,9 +12310,6 @@ package android.content.pm {
|
||||
field public static final int SYNCHRONOUS = 2; // 0x2
|
||||
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
|
||||
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
|
||||
field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
|
||||
field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
|
||||
field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
|
||||
field public static final int VERIFICATION_ALLOW = 1; // 0x1
|
||||
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
|
||||
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
|
||||
|
||||
@@ -2740,6 +2740,7 @@ public class Intent implements Parcelable, Cloneable {
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent by the system.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
|
||||
@@ -2757,6 +2758,7 @@ public class Intent implements Parcelable, Cloneable {
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent by the system.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_PACKAGE_UNSTARTABLE =
|
||||
|
||||
@@ -3824,18 +3824,21 @@ public abstract class PackageManager {
|
||||
* Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
|
||||
* unclear about the cause. This corresponds to a generic alert window shown to the user when
|
||||
* the user attempts to launch the app.
|
||||
* @hide
|
||||
*/
|
||||
public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* Unstartable state due to connection issues that interrupt package loading.
|
||||
* This corresponds to an alert window shown to the user indicating connection errors.
|
||||
* @hide
|
||||
*/
|
||||
public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Unstartable state after encountering storage limitations.
|
||||
* This corresponds to an alert window indicating limited storage.
|
||||
* @hide
|
||||
*/
|
||||
public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
|
||||
|
||||
|
||||
@@ -101,21 +101,18 @@ public final class IncrementalStates {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "received package commit event");
|
||||
}
|
||||
final boolean startableStateChanged;
|
||||
synchronized (mLock) {
|
||||
if (!mStartableState.isStartable()) {
|
||||
mStartableState.adoptNewStartableStateLocked(true);
|
||||
}
|
||||
startableStateChanged = mStartableState.adoptNewStartableStateLocked(true);
|
||||
if (!isIncremental) {
|
||||
updateProgressLocked(1);
|
||||
}
|
||||
}
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportStartableState,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
if (startableStateChanged) {
|
||||
onStartableStateChanged();
|
||||
}
|
||||
if (!isIncremental) {
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportFullyLoaded,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
onLoadingStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +128,7 @@ public final class IncrementalStates {
|
||||
synchronized (mLock) {
|
||||
if (mStartableState.isStartable() && mLoadingState.isLoading()) {
|
||||
// Changing from startable -> unstartable only if app is still loading.
|
||||
mStartableState.adoptNewStartableStateLocked(false);
|
||||
startableStateChanged = true;
|
||||
startableStateChanged = mStartableState.adoptNewStartableStateLocked(false);
|
||||
} else {
|
||||
// If the app is fully loaded, the crash or ANR is caused by the app itself, so
|
||||
// we do not change the startable state.
|
||||
@@ -140,12 +136,15 @@ public final class IncrementalStates {
|
||||
}
|
||||
}
|
||||
if (startableStateChanged) {
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportStartableState,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
onStartableStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void onStartableStateChanged() {
|
||||
// Disable startable state broadcasts
|
||||
// TODO(b/171920377): completely remove unstartable state.
|
||||
}
|
||||
|
||||
private void reportStartableState() {
|
||||
final Callback callback;
|
||||
final boolean startable;
|
||||
@@ -165,6 +164,12 @@ public final class IncrementalStates {
|
||||
}
|
||||
}
|
||||
|
||||
private void onLoadingStateChanged() {
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportFullyLoaded,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
}
|
||||
|
||||
private void reportFullyLoaded() {
|
||||
final Callback callback;
|
||||
synchronized (mLock) {
|
||||
@@ -178,23 +183,20 @@ public final class IncrementalStates {
|
||||
private class StatusConsumer implements Consumer<Integer> {
|
||||
@Override
|
||||
public void accept(Integer storageStatus) {
|
||||
final boolean oldState, newState;
|
||||
final boolean startableStateChanged;
|
||||
synchronized (mLock) {
|
||||
if (!mLoadingState.isLoading()) {
|
||||
// Do nothing if the package is already fully loaded
|
||||
return;
|
||||
}
|
||||
oldState = mStartableState.isStartable();
|
||||
mStorageHealthStatus = storageStatus;
|
||||
updateStartableStateLocked();
|
||||
newState = mStartableState.isStartable();
|
||||
startableStateChanged = updateStartableStateLocked();
|
||||
}
|
||||
if (oldState != newState) {
|
||||
mHandler.post(PooledLambda.obtainRunnable(IncrementalStates::reportStartableState,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
if (startableStateChanged) {
|
||||
onStartableStateChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* By calling this method, the caller indicates that there issues with the Incremental
|
||||
@@ -239,14 +241,10 @@ public final class IncrementalStates {
|
||||
newStartableState = mStartableState.isStartable();
|
||||
}
|
||||
if (!newLoadingState) {
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportFullyLoaded,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
onLoadingStateChanged();
|
||||
}
|
||||
if (newStartableState != oldStartableState) {
|
||||
mHandler.post(PooledLambda.obtainRunnable(
|
||||
IncrementalStates::reportStartableState,
|
||||
IncrementalStates.this).recycleOnUse());
|
||||
onStartableStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,8 +282,9 @@ public final class IncrementalStates {
|
||||
* health
|
||||
* status. If the next state is different from the current state, proceed with state
|
||||
* change.
|
||||
* @return True if the new startable state is different from the old one.
|
||||
*/
|
||||
private void updateStartableStateLocked() {
|
||||
private boolean updateStartableStateLocked() {
|
||||
final boolean currentState = mStartableState.isStartable();
|
||||
boolean nextState = currentState;
|
||||
if (!currentState) {
|
||||
@@ -302,9 +301,9 @@ public final class IncrementalStates {
|
||||
}
|
||||
}
|
||||
if (nextState == currentState) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mStartableState.adoptNewStartableStateLocked(nextState);
|
||||
return mStartableState.adoptNewStartableStateLocked(nextState);
|
||||
}
|
||||
|
||||
private void updateProgressLocked(float progress) {
|
||||
@@ -343,12 +342,30 @@ public final class IncrementalStates {
|
||||
return mUnstartableReason;
|
||||
}
|
||||
|
||||
public void adoptNewStartableStateLocked(boolean nextState) {
|
||||
/**
|
||||
* Adopt new startable state if it is different from the current state.
|
||||
* @param nextState True if startable, false if unstartable.
|
||||
* @return True if the state has changed, false otherwise.
|
||||
*/
|
||||
public boolean adoptNewStartableStateLocked(boolean nextState) {
|
||||
if (mIsStartable == nextState) {
|
||||
return false;
|
||||
}
|
||||
if (!nextState) {
|
||||
// Do nothing if the next state is "unstartable"; keep package always startable.
|
||||
// TODO(b/171920377): completely remove unstartable state.
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Attempting to set startable state to false. Abort.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "startable state changed from " + mIsStartable + " to " + nextState);
|
||||
Slog.i(TAG,
|
||||
"startable state changed from " + mIsStartable + " to " + nextState);
|
||||
}
|
||||
mIsStartable = nextState;
|
||||
mUnstartableReason = getUnstartableReasonLocked();
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getUnstartableReasonLocked() {
|
||||
|
||||
@@ -16478,8 +16478,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
|
||||
healthCheckParams.unhealthyMonitoringMs =
|
||||
INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
|
||||
mIncrementalManager.registerHealthListener(codePath,
|
||||
new StorageHealthCheckParams(), incrementalHealthListener);
|
||||
mIncrementalManager.registerHealthListener(codePath, healthCheckParams,
|
||||
incrementalHealthListener);
|
||||
}
|
||||
|
||||
// Ensure that the uninstall reason is UNKNOWN for users with the package installed.
|
||||
|
||||
@@ -44,7 +44,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class IncrementalStatesTest {
|
||||
private IncrementalStates mIncrementalStates;
|
||||
private ConditionVariable mUnstartableCalled = new ConditionVariable();
|
||||
private ConditionVariable mStartableCalled = new ConditionVariable();
|
||||
private ConditionVariable mFullyLoadedCalled = new ConditionVariable();
|
||||
private AtomicInteger mUnstartableReason = new AtomicInteger(0);
|
||||
private static final int WAIT_TIMEOUT_MILLIS = 1000; /* 1 second */
|
||||
@@ -57,7 +56,6 @@ public class IncrementalStatesTest {
|
||||
|
||||
@Override
|
||||
public void onPackageStartable() {
|
||||
mStartableCalled.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,24 +75,22 @@ public class IncrementalStatesTest {
|
||||
mIncrementalStates.setCallback(mCallback);
|
||||
mIncrementalStates.onCommit(true);
|
||||
// Test that package is now startable and loading
|
||||
assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
assertTrue(mIncrementalStates.isLoading());
|
||||
mStartableCalled.close();
|
||||
mUnstartableCalled.close();
|
||||
mFullyLoadedCalled.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that startable state changes to false when Incremental Storage is unhealthy.
|
||||
* Test that the package is still startable when Incremental Storage is unhealthy.
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_IncrementalStorageUnhealthy() {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
|
||||
// Test that package is now unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
// Test that package is still startable
|
||||
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN, mUnstartableReason.get());
|
||||
}
|
||||
|
||||
@@ -112,72 +108,33 @@ public class IncrementalStatesTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the package becomes unstartable when health status indicate storage issues.
|
||||
* Test that the package is still startable when health status indicate storage issues.
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_IncrementalStorageBlocked() {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_STORAGE);
|
||||
// Test that package is now unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
|
||||
// Test that package is still startable
|
||||
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
|
||||
mUnstartableReason.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the package becomes unstartable when health status indicates transport issues.
|
||||
* Test that the package is still startable when health status indicates transport issues.
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_DataLoaderIntegrityError() {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
|
||||
// Test that package is now unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
|
||||
// Test that package is still startable
|
||||
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
|
||||
mUnstartableReason.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the package becomes unstartable when Incremental Storage is unhealthy, and it
|
||||
* becomes startable again when Incremental Storage is healthy again.
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_IncrementalStorageUnhealthyBackToHealthy()
|
||||
throws InterruptedException {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
|
||||
// Test that package is unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_OK);
|
||||
// Test that package is now startable
|
||||
assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the package becomes unstartable when health status indicates transportation issue,
|
||||
* and it becomes startable again when health status is ok again.
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_DataLoaderUnhealthyBackToHealthy()
|
||||
throws InterruptedException {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
|
||||
// Test that package is unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
|
||||
mIncrementalStates.onStorageHealthStatusChanged(IStorageHealthListener.HEALTH_STATUS_OK);
|
||||
// Test that package is now startable
|
||||
assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when loading progress is 1, the package becomes fully loaded, and the change of
|
||||
* Incremental Storage health status does not affect the startable state.
|
||||
@@ -196,44 +153,12 @@ public class IncrementalStatesTest {
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when loading progress is 1, the package becomes fully loaded, and if the package
|
||||
* was unstartable, it becomes startable.
|
||||
*/
|
||||
@Test
|
||||
public void testLoadingTransition_FullyLoadedWhenUnstartable() throws InterruptedException {
|
||||
mIncrementalStates.onStorageHealthStatusChanged(
|
||||
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
|
||||
// Test that package is unstartable
|
||||
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
// Test that package is still loading
|
||||
assertTrue(mIncrementalStates.isLoading());
|
||||
|
||||
mIncrementalStates.setProgress(0.5f);
|
||||
// Test that package is still unstartable
|
||||
assertFalse(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
mIncrementalStates.setProgress(1.0f);
|
||||
// Test that package is now startable
|
||||
assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
// Test that package is now fully loaded
|
||||
assertTrue(mFullyLoadedCalled.block(WAIT_TIMEOUT_MILLIS));
|
||||
assertFalse(mIncrementalStates.isLoading());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test startability transitions if app crashes or anrs
|
||||
*/
|
||||
@Test
|
||||
public void testStartableTransition_AppCrashOrAnr() {
|
||||
mIncrementalStates.onCrashOrAnr();
|
||||
assertFalse(mIncrementalStates.isStartable());
|
||||
mIncrementalStates.setProgress(1.0f);
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
mIncrementalStates.onCrashOrAnr();
|
||||
// Test that if fully loaded, app remains startable even if it has crashed
|
||||
assertTrue(mIncrementalStates.isStartable());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user