Merge "[incremental/pm] set health listener on commit and on reboot"
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 52475e9..ca92ad5 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -144,4 +144,14 @@
* Stop listening for the loading progress change for a storage.
*/
boolean unregisterLoadingProgressListener(int storageId);
+
+ /**
+ * Register storage health status listener.
+ */
+ boolean registerStorageHealthListener(int storageId, in StorageHealthCheckParams params, in IStorageHealthListener listener);
+
+ /**
+ * Register storage health status listener.
+ */
+ void unregisterStorageHealthListener(int storageId);
}
diff --git a/core/java/android/os/incremental/IStorageHealthListener.aidl b/core/java/android/os/incremental/IStorageHealthListener.aidl
index 9f93ede..c71e73f 100644
--- a/core/java/android/os/incremental/IStorageHealthListener.aidl
+++ b/core/java/android/os/incremental/IStorageHealthListener.aidl
@@ -26,9 +26,15 @@
/** There are reads pending for params.blockedTimeoutMs, waiting till
* params.unhealthyTimeoutMs to confirm unhealthy state. */
const int HEALTH_STATUS_BLOCKED = 2;
- /** There are reads pending for params.unhealthyTimeoutMs>,
- * marking storage as unhealthy. */
+ /** There are reads pending for params.unhealthyTimeoutMs,
+ * marking storage as unhealthy due to unknown issues. */
const int HEALTH_STATUS_UNHEALTHY = 3;
+ /** There are reads pending for params.unhealthyTimeoutMs,
+ * due to data transportation issues. */
+ const int HEALTH_STATUS_UNHEALTHY_TRANSPORT = 4;
+ /** There are reads pending for params.unhealthyTimeoutMs,
+ * due to limited storage space. */
+ const int HEALTH_STATUS_UNHEALTHY_STORAGE = 5;
/** Health status callback. */
void onHealthStatus(in int storageId, in int status);
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 768ef97..fb47ef0 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -283,6 +283,7 @@
return;
}
mLoadingProgressCallbacks.cleanUpCallbacks(storage);
+ unregisterHealthListener(codePath);
mService.deleteStorage(storage.getId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -297,7 +298,7 @@
* @param callback To report loading progress to.
* @return True if the package name and associated storage id are valid. False otherwise.
*/
- public boolean registerCallback(@NonNull String codePath,
+ public boolean registerLoadingProgressCallback(@NonNull String codePath,
@NonNull IPackageLoadingProgressCallback callback) {
final IncrementalStorage storage = openStorage(codePath);
if (storage == null) {
@@ -314,7 +315,7 @@
* @param codePath Path of the installed package
* @return True if the package name and associated storage id are valid. False otherwise.
*/
- public boolean unregisterCallback(@NonNull String codePath,
+ public boolean unregisterLoadingProgressCallback(@NonNull String codePath,
@NonNull IPackageLoadingProgressCallback callback) {
final IncrementalStorage storage = openStorage(codePath);
if (storage == null) {
@@ -414,6 +415,38 @@
}
}
+ /**
+ * Specify the health check params and listener for listening to Incremental Storage health
+ * status changes. Notice that this will overwrite the previously registered listener.
+ * @param codePath Path of the installed package. This path is on an Incremental Storage.
+ * @param healthCheckParams The params for health state change timeouts.
+ * @param listener To report health status change.
+ * @return True if listener was successfully registered.
+ */
+ public boolean registerHealthListener(@NonNull String codePath,
+ @NonNull StorageHealthCheckParams healthCheckParams,
+ @NonNull IStorageHealthListener.Stub listener) {
+ final IncrementalStorage storage = openStorage(codePath);
+ if (storage == null) {
+ // storage does not exist, package not installed
+ return false;
+ }
+ return storage.registerStorageHealthListener(healthCheckParams, listener);
+ }
+
+ /**
+ * Stop listening to health status changes on an Incremental Storage.
+ * @param codePath Path of the installed package. This path is on an Incremental Storage.
+ */
+ public void unregisterHealthListener(@NonNull String codePath) {
+ final IncrementalStorage storage = openStorage(codePath);
+ if (storage == null) {
+ // storage does not exist, package not installed
+ return;
+ }
+ storage.unregisterStorageHealthListener();
+ }
+
/* Native methods */
private static native boolean nativeIsEnabled();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index a1c3cc6..b913faf 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -545,4 +545,31 @@
return false;
}
}
+
+ /**
+ * Register to listen to the status changes of the storage health.
+ * @param healthCheckParams Params to specify status change timeouts.
+ * @param listener To report health status change from Incremental Service to the caller.
+ */
+ public boolean registerStorageHealthListener(StorageHealthCheckParams healthCheckParams,
+ IStorageHealthListener listener) {
+ try {
+ return mService.registerStorageHealthListener(mId, healthCheckParams, listener);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
+ /**
+ * Stops listening to the status changes of the storage health.
+ */
+ public void unregisterStorageHealthListener() {
+ try {
+ mService.unregisterStorageHealthListener(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index ababb83..43f4a34 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -16,18 +16,21 @@
package com.android.server.pm;
-import android.content.pm.IDataLoaderStatusListener;
+import static android.os.incremental.IStorageHealthListener.HEALTH_STATUS_OK;
+import static android.os.incremental.IStorageHealthListener.HEALTH_STATUS_UNHEALTHY;
+import static android.os.incremental.IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_STORAGE;
+import static android.os.incremental.IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT;
+
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.os.incremental.IStorageHealthListener;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;
-import java.util.function.BiConsumer;
+import java.util.function.Consumer;
/**
* Manages state transitions of a package installed on Incremental File System. Currently manages:
@@ -36,8 +39,7 @@
*
* The following events might change the states of a package:
* 1. Installation commit
- * 2. Incremental storage health
- * 3. Data loader stream health
+ * 2. Incremental storage health changes
* 4. Loading progress changes
*
* @hide
@@ -48,16 +50,14 @@
private final Handler mHandler = BackgroundThread.getHandler();
private final Object mLock = new Object();
@GuardedBy("mLock")
- private int mStreamStatus = IDataLoaderStatusListener.STREAM_HEALTHY;
- @GuardedBy("mLock")
- private int mStorageHealthStatus = IStorageHealthListener.HEALTH_STATUS_OK;
+ private int mStorageHealthStatus = HEALTH_STATUS_OK;
@GuardedBy("mLock")
private final LoadingState mLoadingState;
@GuardedBy("mLock")
private StartableState mStartableState;
@GuardedBy("mLock")
private Callback mCallback = null;
- private final BiConsumer<Integer, Integer> mStatusConsumer;
+ private final Consumer<Integer> mStatusConsumer;
public IncrementalStates() {
// By default the package is not startable and not fully loaded (i.e., is loading)
@@ -148,12 +148,9 @@
}
}
- private class StatusConsumer implements BiConsumer<Integer, Integer> {
+ private class StatusConsumer implements Consumer<Integer> {
@Override
- public void accept(Integer streamStatus, Integer storageStatus) {
- if (streamStatus == null && storageStatus == null) {
- return;
- }
+ public void accept(Integer storageStatus) {
final boolean oldState, newState;
synchronized (mLock) {
if (!mLoadingState.isLoading()) {
@@ -161,12 +158,7 @@
return;
}
oldState = mStartableState.isStartable();
- if (streamStatus != null) {
- mStreamStatus = (Integer) streamStatus;
- }
- if (storageStatus != null) {
- mStorageHealthStatus = (Integer) storageStatus;
- }
+ mStorageHealthStatus = storageStatus;
updateStartableStateLocked();
newState = mStartableState.isStartable();
}
@@ -188,21 +180,7 @@
Slog.i(TAG, "received storage health status changed event : storageHealthStatus="
+ storageHealthStatus);
}
- mStatusConsumer.accept(null, storageHealthStatus);
- }
-
- /**
- * By calling this method, the caller indicates that the stream status of the package has
- * been
- * changed. This could indicate a streaming error. The state will change according to the
- * status
- * code defined in {@code IDataLoaderStatusListener}.
- */
- public void onStreamStatusChanged(int streamState) {
- if (DEBUG) {
- Slog.i(TAG, "received stream status changed event : streamState=" + streamState);
- }
- mStatusConsumer.accept(streamState, null);
+ mStatusConsumer.accept(storageHealthStatus);
}
/**
@@ -284,35 +262,16 @@
final boolean currentState = mStartableState.isStartable();
boolean nextState = currentState;
if (!currentState) {
- if (mStorageHealthStatus == IStorageHealthListener.HEALTH_STATUS_OK
- && mStreamStatus == IDataLoaderStatusListener.STREAM_HEALTHY) {
- // change from unstartable -> startable when both stream and storage are healthy
+ if (mStorageHealthStatus == HEALTH_STATUS_OK) {
+ // change from unstartable -> startable
nextState = true;
}
} else {
- if (mStorageHealthStatus == IStorageHealthListener.HEALTH_STATUS_UNHEALTHY) {
- // unrecoverable if storage is unhealthy
+ if (mStorageHealthStatus == HEALTH_STATUS_UNHEALTHY
+ || mStorageHealthStatus == HEALTH_STATUS_UNHEALTHY_STORAGE
+ || mStorageHealthStatus == HEALTH_STATUS_UNHEALTHY_TRANSPORT) {
+ // change from startable -> unstartable
nextState = false;
- } else {
- switch (mStreamStatus) {
- case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
- // unrecoverable, fall through
- case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
- // unrecoverable
- nextState = false;
- break;
- }
- case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
- if (mStorageHealthStatus != IStorageHealthListener.HEALTH_STATUS_OK) {
- // unrecoverable if there is a pending read AND storage is limited
- nextState = false;
- }
- break;
- }
- default:
- // anything else, remain startable
- break;
- }
}
}
if (nextState == currentState) {
@@ -370,17 +329,11 @@
return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
}
// Translate stream status to reason for unstartable state
- switch (mStreamStatus) {
- case IDataLoaderStatusListener.STREAM_TRANSPORT_ERROR:
- // fall through
- case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
- // fall through
- case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
- return PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR;
- }
- case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
+ switch (mStorageHealthStatus) {
+ case HEALTH_STATUS_UNHEALTHY_STORAGE:
return PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE;
- }
+ case HEALTH_STATUS_UNHEALTHY_TRANSPORT:
+ return PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR;
default:
return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
}
@@ -464,7 +417,6 @@
}
IncrementalStates l = (IncrementalStates) o;
return l.mStorageHealthStatus == mStorageHealthStatus
- && l.mStreamStatus == mStreamStatus
&& l.mStartableState.equals(mStartableState)
&& l.mLoadingState.equals(mLoadingState);
}
@@ -474,7 +426,6 @@
int hashCode = mStartableState.hashCode();
hashCode = 31 * hashCode + mLoadingState.hashCode();
hashCode = 31 * hashCode + mStorageHealthStatus;
- hashCode = 31 * hashCode + mStreamStatus;
return hashCode;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 649cafb..5d2928e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -143,7 +143,6 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
@@ -1702,28 +1701,6 @@
dispatchSessionFinished(error, detailedMessage, null);
}
- private void onStorageHealthStatusChanged(int status) {
- final String packageName = getPackageName();
- if (TextUtils.isEmpty(packageName)) {
- // The package has not been installed.
- return;
- }
- mHandler.post(PooledLambda.obtainRunnable(
- PackageManagerService::onStorageHealthStatusChanged,
- mPm, packageName, status, userId).recycleOnUse());
- }
-
- private void onStreamHealthStatusChanged(int status) {
- final String packageName = getPackageName();
- if (TextUtils.isEmpty(packageName)) {
- // The package has not been installed.
- return;
- }
- mHandler.post(PooledLambda.obtainRunnable(
- PackageManagerService::onStreamStatusChanged,
- mPm, packageName, status, userId).recycleOnUse());
- }
-
/**
* If session should be sealed, then it's sealed to prevent further modification.
* If the session can't be sealed then it's destroyed.
@@ -3315,19 +3292,11 @@
return;
}
- final boolean isDestroyedOrDataLoaderFinished;
synchronized (mLock) {
- isDestroyedOrDataLoaderFinished = mDestroyed || mDataLoaderFinished;
- }
- if (isDestroyedOrDataLoaderFinished) {
- switch (status) {
- case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
- // treat as unhealthy storage
- onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- return;
+ if (mDestroyed || mDataLoaderFinished) {
+ // No need to worry about post installation
+ return;
}
- return;
}
try {
@@ -3423,13 +3392,10 @@
}
@Override
public void reportStreamHealth(int dataLoaderId, int streamStatus) {
- synchronized (mLock) {
- if (!mDestroyed && !mDataLoaderFinished) {
- // ignore streaming status if package isn't installed
- return;
- }
- }
- onStreamHealthStatusChanged(streamStatus);
+ // Currently the stream status is not used during package installation. It is
+ // technically possible for the data loader to report stream status via this
+ // callback, but if something is wrong with the streaming, it is more likely that
+ // prepareDataLoaderLocked will return false and the installation will be aborted.
}
};
@@ -3438,20 +3404,16 @@
healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
-
final boolean systemDataLoader =
params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
@Override
public void onHealthStatus(int storageId, int status) {
- final boolean isDestroyedOrDataLoaderFinished;
synchronized (mLock) {
- isDestroyedOrDataLoaderFinished = mDestroyed || mDataLoaderFinished;
- }
- if (isDestroyedOrDataLoaderFinished) {
- // App's installed.
- onStorageHealthStatusChanged(status);
- return;
+ if (mDestroyed || mDataLoaderFinished) {
+ // No need to worry about post installation
+ return;
+ }
}
switch (status) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff84e2e..2ea8008 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -271,8 +271,10 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
+import android.os.incremental.IStorageHealthListener;
import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
+import android.os.incremental.StorageHealthCheckParams;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
@@ -732,6 +734,14 @@
private static final String RANDOM_DIR_PREFIX = "~~";
+ /**
+ * Timeout configurations for incremental storage health monitor.
+ * See {@link IStorageHealthListener}
+ */
+ private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000;
+ private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
+ private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
+
final ServiceThread mHandlerThread;
final Handler mHandler;
@@ -9696,6 +9706,18 @@
mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
}
}
+ if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
+ if (pkgSetting != null && pkgSetting.isPackageLoading()) {
+ final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
+ healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
+ healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
+ healthCheckParams.unhealthyMonitoringMs =
+ INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
+ mIncrementalManager.registerHealthListener(parsedPackage.getPath(),
+ healthCheckParams,
+ new IncrementalHealthListener(parsedPackage.getPackageName()));
+ }
+ }
return scanResult.pkgSetting.pkg;
}
@@ -16356,12 +16378,25 @@
// TODO(b/169721400): generalize Incremental States and create a Callback object
// that can be used for all the packages.
- final IncrementalStatesCallback incrementalStatesCallback =
- new IncrementalStatesCallback(ps, userId);
final String codePath = ps.getPathString();
if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) {
- mIncrementalManager.registerCallback(codePath, incrementalStatesCallback);
+ final IncrementalStatesCallback incrementalStatesCallback =
+ new IncrementalStatesCallback(ps.name,
+ UserHandle.getUid(userId, ps.appId),
+ getInstalledUsers(ps, userId));
ps.setIncrementalStatesCallback(incrementalStatesCallback);
+ mIncrementalManager.registerLoadingProgressCallback(codePath,
+ new IncrementalProgressListener(ps.name));
+ final IncrementalHealthListener incrementalHealthListener =
+ new IncrementalHealthListener(ps.name);
+ final StorageHealthCheckParams healthCheckParams =
+ new StorageHealthCheckParams();
+ healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
+ healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
+ healthCheckParams.unhealthyMonitoringMs =
+ INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
+ mIncrementalManager.registerHealthListener(codePath,
+ new StorageHealthCheckParams(), incrementalHealthListener);
}
// Ensure that the uninstall reason is UNKNOWN for users with the package installed.
@@ -17264,45 +17299,39 @@
NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
}
- private class IncrementalStatesCallback extends IPackageLoadingProgressCallback.Stub
- implements IncrementalStates.Callback {
- @GuardedBy("mPackageSetting")
- private final PackageSetting mPackageSetting;
- private final String mPackageName;
- private final String mPathString;
- private final int mUid;
- private final int[] mInstalledUserIds;
-
- IncrementalStatesCallback(PackageSetting packageSetting, int userId) {
- mPackageSetting = packageSetting;
- mPackageName = packageSetting.name;
- mUid = UserHandle.getUid(userId, packageSetting.appId);
- mPathString = packageSetting.getPathString();
- final int[] allUserIds = resolveUserIds(userId);
- final ArrayList<Integer> installedUserIds = new ArrayList<>();
- for (int i = 0; i < allUserIds.length; i++) {
- if (packageSetting.getInstalled(allUserIds[i])) {
- installedUserIds.add(allUserIds[i]);
- }
- }
- final int numInstalledUserId = installedUserIds.size();
- mInstalledUserIds = new int[numInstalledUserId];
- for (int i = 0; i < numInstalledUserId; i++) {
- mInstalledUserIds[i] = installedUserIds.get(i);
+ private int[] getInstalledUsers(PackageSetting ps, int userId) {
+ final int[] allUserIds = resolveUserIds(userId);
+ final ArrayList<Integer> installedUserIdsList = new ArrayList<>();
+ for (int i = 0; i < allUserIds.length; i++) {
+ if (ps.getInstalled(allUserIds[i])) {
+ installedUserIdsList.add(allUserIds[i]);
}
}
+ final int numInstalledUserId = installedUserIdsList.size();
+ final int[] installedUserIds = new int[numInstalledUserId];
+ for (int i = 0; i < numInstalledUserId; i++) {
+ installedUserIds[i] = installedUserIdsList.get(i);
+ }
+ return installedUserIds;
+ }
- @Override
- public void onPackageLoadingProgressChanged(float progress) {
- synchronized (mPackageSetting) {
- mPackageSetting.setLoadingProgress(progress);
- }
+ /**
+ * Package states callback, used to listen for package state changes and send broadcasts
+ */
+ private final class IncrementalStatesCallback implements IncrementalStates.Callback {
+ private final String mPackageName;
+ private final int mUid;
+ private final int[] mInstalledUserIds;
+ IncrementalStatesCallback(String packageName, int uid, int[] installedUserIds) {
+ mPackageName = packageName;
+ mUid = uid;
+ mInstalledUserIds = installedUserIds;
}
@Override
public void onPackageFullyLoaded() {
- mIncrementalManager.unregisterCallback(mPathString, this);
final SparseArray<int[]> newBroadcastAllowList;
+ final String codePath;
synchronized (mLock) {
final PackageSetting ps = mSettings.mPackages.get(mPackageName);
if (ps == null) {
@@ -17310,6 +17339,7 @@
}
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
ps, mInstalledUserIds, mSettings.mPackages);
+ codePath = ps.getPathString();
}
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, mUid);
@@ -17318,6 +17348,8 @@
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
mInstalledUserIds, null /* instantUserIds */, newBroadcastAllowList);
+ // Unregister health listener as it will always be healthy from now
+ mIncrementalManager.unregisterHealthListener(codePath);
}
@Override
@@ -17365,37 +17397,48 @@
}
/**
- * This is an internal method that is used to indicate changes on the health status of the
- * Incremental Storage used by an installed package with an associated user id. This might
- * result in a change in the loading state of the package.
+ * Loading progress callback, used to listen for progress changes and update package setting
*/
- public void onStorageHealthStatusChanged(String packageName, int status, int userId) {
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, true, false,
- "onStorageHealthStatusChanged");
- final PackageSetting ps = getPackageSettingForUser(packageName, callingUid, userId);
- if (ps == null) {
- return;
+ private class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
+ private final String mPackageName;
+ IncrementalProgressListener(String packageName) {
+ mPackageName = packageName;
}
- ps.setStorageHealthStatus(status);
+
+ @Override
+ public void onPackageLoadingProgressChanged(float progress) {
+ final PackageSetting ps;
+ synchronized (mLock) {
+ ps = mSettings.mPackages.get(mPackageName);
+ }
+ if (ps == null) {
+ return;
+ }
+ ps.setLoadingProgress(progress);
+ }
}
/**
- * This is an internal method that is used to indicate changes on the stream status of the
- * data loader used by an installed package with an associated user id. This might
- * result in a change in the loading state of the package.
+ * Incremental storage health status callback, used to listen for monitoring changes and update
+ * package setting.
*/
- public void onStreamStatusChanged(String packageName, int status, int userId) {
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.enforceCrossUserPermission(
- callingUid, userId, true, false,
- "onStreamStatusChanged");
- final PackageSetting ps = getPackageSettingForUser(packageName, callingUid, userId);
- if (ps == null) {
- return;
+ private class IncrementalHealthListener extends IStorageHealthListener.Stub {
+ private final String mPackageName;
+ IncrementalHealthListener(String packageName) {
+ mPackageName = packageName;
}
- ps.setStreamStatus(status);
+
+ @Override
+ public void onHealthStatus(int storageId, int status) throws RemoteException {
+ final PackageSetting ps;
+ synchronized (mLock) {
+ ps = mSettings.mPackages.get(mPackageName);
+ }
+ if (ps == null) {
+ return;
+ }
+ ps.setStorageHealthStatus(status);
+ }
}
@Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid,
@@ -25637,7 +25680,7 @@
"Failed registering loading progress callback. Incremental is not enabled");
return false;
}
- return mIncrementalManager.registerCallback(ps.getPathString(),
+ return mIncrementalManager.registerLoadingProgressCallback(ps.getPathString(),
(IPackageLoadingProgressCallback) callback.getBinder());
}
@@ -25656,7 +25699,7 @@
if (mIncrementalManager == null) {
return false;
}
- return mIncrementalManager.unregisterCallback(ps.getPathString(),
+ return mIncrementalManager.unregisterLoadingProgressCallback(ps.getPathString(),
(IPackageLoadingProgressCallback) callback.getBinder());
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index d52ad46..be7c7c6 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -793,13 +793,6 @@
incrementalStates.onStorageHealthStatusChanged(status);
}
- /**
- * @see IncrementalStates#onStreamStatusChanged(int)
- */
- public void setStreamStatus(int status) {
- incrementalStates.onStreamStatusChanged(status);
- }
-
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
setPath(other.getPath());
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 2f8825b..a31aac9 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -323,6 +323,22 @@
return ok();
}
+binder::Status BinderIncrementalService::registerStorageHealthListener(
+ int32_t storageId,
+ const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
+ const ::android::sp<IStorageHealthListener>& healthListener, bool* _aidl_return) {
+ *_aidl_return = mImpl.registerStorageHealthListener(storageId,
+ const_cast<StorageHealthCheckParams&&>(
+ healthCheckParams),
+ healthListener);
+ return ok();
+}
+
+binder::Status BinderIncrementalService::unregisterStorageHealthListener(int32_t storageId) {
+ mImpl.unregisterStorageHealthListener(storageId);
+ return ok();
+}
+
} // namespace android::os::incremental
jlong Incremental_IncrementalService_Start(JNIEnv* env) {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 0a89166..8afa0f7 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -89,6 +89,11 @@
progressListener,
bool* _aidl_return) final;
binder::Status unregisterLoadingProgressListener(int32_t storageId, bool* _aidl_return) final;
+ binder::Status registerStorageHealthListener(
+ int32_t storageId,
+ const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams,
+ const ::android::sp<IStorageHealthListener>& healthListener, bool* _aidl_return) final;
+ binder::Status unregisterStorageHealthListener(int32_t storageId) final;
private:
android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 5f145f3..599ac93 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1801,6 +1801,31 @@
return removeTimedJobs(*mProgressUpdateJobQueue, storage);
}
+bool IncrementalService::registerStorageHealthListener(
+ StorageId storage, StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener) {
+ DataLoaderStubPtr dataLoaderStub;
+ {
+ std::unique_lock l(mLock);
+ const auto& ifs = getIfsLocked(storage);
+ if (!ifs) {
+ return false;
+ }
+ dataLoaderStub = ifs->dataLoaderStub;
+ if (!dataLoaderStub) {
+ return false;
+ }
+ }
+ dataLoaderStub->setHealthListener(std::move(healthCheckParams), &healthListener);
+ return true;
+}
+
+void IncrementalService::unregisterStorageHealthListener(StorageId storage) {
+ StorageHealthCheckParams invalidCheckParams;
+ invalidCheckParams.blockedTimeoutMs = -1;
+ registerStorageHealthListener(storage, std::move(invalidCheckParams), {});
+}
+
bool IncrementalService::perfLoggingEnabled() {
static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
return enabled;
@@ -2137,6 +2162,19 @@
binder::Status IncrementalService::DataLoaderStub::reportStreamHealth(MountId mountId,
int newStatus) {
+ if (!isValid()) {
+ return binder::Status::
+ fromServiceSpecificError(-EINVAL,
+ "reportStreamHealth came to invalid DataLoaderStub");
+ }
+ if (id() != mountId) {
+ LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
+ return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
+ }
+ {
+ std::lock_guard lock(mMutex);
+ mStreamStatus = newStatus;
+ }
return binder::Status::ok();
}
@@ -2153,6 +2191,33 @@
}
}
+static int adjustHealthStatus(int healthStatus, int streamStatus) {
+ if (healthStatus == IStorageHealthListener::HEALTH_STATUS_OK) {
+ // everything is good; no need to change status
+ return healthStatus;
+ }
+ int newHeathStatus = healthStatus;
+ switch (streamStatus) {
+ case IDataLoaderStatusListener::STREAM_STORAGE_ERROR:
+ // storage is limited and storage not healthy
+ newHeathStatus = IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_STORAGE;
+ break;
+ case IDataLoaderStatusListener::STREAM_INTEGRITY_ERROR:
+ // fall through
+ case IDataLoaderStatusListener::STREAM_SOURCE_ERROR:
+ // fall through
+ case IDataLoaderStatusListener::STREAM_TRANSPORT_ERROR:
+ if (healthStatus == IStorageHealthListener::HEALTH_STATUS_UNHEALTHY) {
+ newHeathStatus = IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_TRANSPORT;
+ }
+ // pending/blocked status due to transportation issues is not regarded as unhealthy
+ break;
+ default:
+ break;
+ }
+ return newHeathStatus;
+}
+
void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {
LOG(DEBUG) << id() << ": updateHealthStatus" << (baseline ? " (baseline)" : "");
@@ -2232,6 +2297,8 @@
checkBackAfter = unhealthyMonitoring;
healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_UNHEALTHY;
}
+ // Adjust health status based on stream status
+ healthStatusToReport = adjustHealthStatus(healthStatusToReport, mStreamStatus);
LOG(DEBUG) << id() << ": updateHealthStatus in " << double(checkBackAfter.count()) / 1000.0
<< "secs";
mService.addTimedJob(*mService.mTimedQueue, id(), checkBackAfter,
@@ -2321,6 +2388,18 @@
mService.mLooper->wake();
}
+void IncrementalService::DataLoaderStub::setHealthListener(
+ StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener* healthListener) {
+ std::lock_guard lock(mMutex);
+ mHealthCheckParams = std::move(healthCheckParams);
+ if (healthListener == nullptr) {
+ // reset listener and params
+ mHealthListener = {};
+ } else {
+ mHealthListener = *healthListener;
+ }
+}
+
void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " dataLoader: {\n");
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 504c02a..4c4b8bd 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -140,7 +140,10 @@
bool registerLoadingProgressListener(StorageId storage,
const StorageLoadingProgressListener& progressListener);
bool unregisterLoadingProgressListener(StorageId storage);
-
+ bool registerStorageHealthListener(StorageId storage,
+ StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener& healthListener);
+ void unregisterStorageHealthListener(StorageId storage);
RawMetadata getMetadata(StorageId storage, std::string_view path) const;
RawMetadata getMetadata(StorageId storage, FileId node) const;
@@ -197,6 +200,8 @@
MountId id() const { return mId.load(std::memory_order_relaxed); }
const content::pm::DataLoaderParamsParcel& params() const { return mParams; }
+ void setHealthListener(StorageHealthCheckParams&& healthCheckParams,
+ const StorageHealthListener* healthListener);
private:
binder::Status onStatusChanged(MountId mount, int newStatus) final;
@@ -251,6 +256,7 @@
BootClockTsUs kernelTsUs;
} mHealthBase = {TimePoint::max(), kMaxBootClockTsUs};
StorageHealthCheckParams mHealthCheckParams;
+ int mStreamStatus = content::pm::IDataLoaderStatusListener::STREAM_HEALTHY;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index aec9fa1..867312e 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -177,6 +177,18 @@
}
return binder::Status::ok();
}
+ binder::Status storageError(int32_t id) {
+ if (mListener) {
+ mListener->reportStreamHealth(id, IDataLoaderStatusListener::STREAM_STORAGE_ERROR);
+ }
+ return binder::Status::ok();
+ }
+ binder::Status transportError(int32_t id) {
+ if (mListener) {
+ mListener->reportStreamHealth(id, IDataLoaderStatusListener::STREAM_INTEGRITY_ERROR);
+ }
+ return binder::Status::ok();
+ }
int32_t setStorageParams(bool enableReadLogs) {
int32_t result = -1;
EXPECT_NE(mServiceConnector.get(), nullptr);
@@ -1221,4 +1233,83 @@
EXPECT_CALL(*listenerMock, onStorageLoadingProgressChanged(_, _)).Times(0);
mIncrementalService->registerLoadingProgressListener(storageId, listener);
}
+
+TEST_F(IncrementalServiceTest, testRegisterStorageHealthListenerSuccess) {
+ mIncFs->openMountSuccess();
+ sp<NiceMock<MockStorageHealthListener>> listener{new NiceMock<MockStorageHealthListener>};
+ sp<NiceMock<MockStorageHealthListener>> newListener{new NiceMock<MockStorageHealthListener>};
+ NiceMock<MockStorageHealthListener>* newListenerMock = newListener.get();
+
+ TemporaryDir tempDir;
+ int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ IncrementalService::CreateOptions::CreateNew,
+ {}, StorageHealthCheckParams{}, listener);
+ ASSERT_GE(storageId, 0);
+ StorageHealthCheckParams newParams;
+ newParams.blockedTimeoutMs = 10000;
+ newParams.unhealthyTimeoutMs = 20000;
+ newParams.unhealthyMonitoringMs = 30000;
+ ASSERT_TRUE(mIncrementalService->registerStorageHealthListener(storageId, std::move(newParams),
+ newListener));
+
+ using MS = std::chrono::milliseconds;
+ using MCS = std::chrono::microseconds;
+
+ const auto blockedTimeout = MS(newParams.blockedTimeoutMs);
+ const auto unhealthyTimeout = MS(newParams.unhealthyTimeoutMs);
+
+ const uint64_t kFirstTimestampUs = 1000000000ll;
+ const uint64_t kBlockedTimestampUs =
+ kFirstTimestampUs - std::chrono::duration_cast<MCS>(blockedTimeout).count();
+ const uint64_t kUnhealthyTimestampUs =
+ kFirstTimestampUs - std::chrono::duration_cast<MCS>(unhealthyTimeout).count();
+
+ // test that old listener was not called
+ EXPECT_CALL(*listener.get(),
+ onHealthStatus(_, IStorageHealthListener::HEALTH_STATUS_READS_PENDING))
+ .Times(0);
+ EXPECT_CALL(*newListenerMock,
+ onHealthStatus(_, IStorageHealthListener::HEALTH_STATUS_READS_PENDING))
+ .Times(1);
+ EXPECT_CALL(*newListenerMock, onHealthStatus(_, IStorageHealthListener::HEALTH_STATUS_BLOCKED))
+ .Times(1);
+ EXPECT_CALL(*newListenerMock,
+ onHealthStatus(_, IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_STORAGE))
+ .Times(1);
+ EXPECT_CALL(*newListenerMock,
+ onHealthStatus(_, IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_TRANSPORT))
+ .Times(1);
+ mIncFs->waitForPendingReadsSuccess(kFirstTimestampUs);
+ mLooper->mCallback(-1, -1, mLooper->mCallbackData);
+
+ ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_READS_PENDING, newListener->mStatus);
+ ASSERT_EQ(storageId, newListener->mStorageId);
+
+ auto timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // test when health status is blocked with transport error
+ mDataLoader->transportError(storageId);
+ mIncFs->waitForPendingReadsSuccess(kBlockedTimestampUs);
+ timedCallback();
+ ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_BLOCKED, newListener->mStatus);
+ timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // test when health status is blocked with storage error
+ mDataLoader->storageError(storageId);
+ mIncFs->waitForPendingReadsSuccess(kBlockedTimestampUs);
+ timedCallback();
+ ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_STORAGE, newListener->mStatus);
+ timedCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // test when health status is unhealthy with transport error
+ mDataLoader->transportError(storageId);
+ mIncFs->waitForPendingReadsSuccess(kUnhealthyTimestampUs);
+ timedCallback();
+ ASSERT_EQ(IStorageHealthListener::HEALTH_STATUS_UNHEALTHY_TRANSPORT, newListener->mStatus);
+ mTimedQueue->clearJob(storageId);
+}
+
} // namespace android::os::incremental
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index c4c2f68..86758f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.content.pm.IDataLoaderStatusListener;
import android.content.pm.PackageManager;
import android.os.ConditionVariable;
import android.os.incremental.IStorageHealthListener;
@@ -113,36 +112,26 @@
}
/**
- * Test that the package is still startable when Incremental Storage is at blocked status.
+ * Test that the package becomes unstartable when health status indicate storage issues.
*/
@Test
public void testStartableTransition_IncrementalStorageBlocked() {
mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_BLOCKED);
- // Test that package is still startable
- assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ 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,
+ mUnstartableReason.get());
}
/**
- * Test that the package is still startable when Data Loader has unknown transportation issues.
- */
- @Test
- public void testStartableTransition_DataLoaderTransportError() {
- mIncrementalStates.onStreamStatusChanged(
- IDataLoaderStatusListener.STREAM_TRANSPORT_ERROR);
- // Test that package is still startable
- assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- }
-
- /**
- * Test that the package becomes unstartable when Data Loader has data integrity issues.
+ * Test that the package becomes unstartable when health status indicates transport issues.
*/
@Test
public void testStartableTransition_DataLoaderIntegrityError() {
- mIncrementalStates.onStreamStatusChanged(
- IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR);
+ mIncrementalStates.onStorageHealthStatusChanged(
+ IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
@@ -151,62 +140,6 @@
}
/**
- * Test that the package becomes unstartable when Data Loader has data source issues.
- */
- @Test
- public void testStartableTransition_DataLoaderSourceError() {
- mIncrementalStates.onStreamStatusChanged(
- IDataLoaderStatusListener.STREAM_SOURCE_ERROR);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
- mUnstartableReason.get());
- }
-
- /**
- * Test that the package becomes unstartable when Data Loader hits limited storage while
- * Incremental storage has a pending reads.
- */
- @Test
- public void testStartableTransition_DataLoaderStorageErrorWhenIncrementalStoragePending()
- throws InterruptedException {
- mIncrementalStates.onStreamStatusChanged(
- IDataLoaderStatusListener.STREAM_STORAGE_ERROR);
- // Test that package is still startable
- assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_READS_PENDING);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
- mUnstartableReason.get());
- }
-
- /**
- * Test that the package becomes unstartable when Data Loader hits limited storage while
- * Incremental storage is at blocked status.
- */
- @Test
- public void testStartableTransition_DataLoaderStorageErrorWhenIncrementalStorageBlocked()
- throws InterruptedException {
- mIncrementalStates.onStreamStatusChanged(
- IDataLoaderStatusListener.STREAM_STORAGE_ERROR);
- // Test that package is still startable
- assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_BLOCKED);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
- mUnstartableReason.get());
- }
-
- /**
* Test that the package becomes unstartable when Incremental Storage is unhealthy, and it
* becomes startable again when Incremental Storage is healthy again.
*/
@@ -227,42 +160,18 @@
}
/**
- * Test that the package becomes unstartable when Data Loader has data integrity issue, and it
- * becomes startable again when Data Loader is healthy again.
+ * 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.onStreamStatusChanged(IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
-
- mIncrementalStates.onStreamStatusChanged(IDataLoaderStatusListener.STREAM_HEALTHY);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- }
-
- /**
- * Test that the package becomes unstartable when both Incremental Storage and Data Loader
- * are unhealthy, and it becomes startable again when both Incremental Storage and Data Loader
- * are healthy again.
- */
- @Test
- public void testStartableTransition_DataLoaderAndIncrementalStorageUnhealthyBackToHealthy()
- throws InterruptedException {
mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- mIncrementalStates.onStreamStatusChanged(IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR);
+ IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
// Test that package is unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- mIncrementalStates.onStreamStatusChanged(IDataLoaderStatusListener.STREAM_HEALTHY);
- // Test that package is still unstartable
- assertFalse(mStartableCalled.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));