Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2570ec01 authored by Songchun Fan's avatar Songchun Fan
Browse files

[incremental/pm] set health listener on commit and on reboot

This changes allow Incremental Service to directly report health status
to package manager service.

A health listener is created during package installation session to
monitor incremental storage health. After commit, a new listener is
created and will overwrite the old one.

The new listener will listen to incremental storage health and report
the status to package manager service, which will then send the status
to IncrementalStates, where the startability state and unstartable
reason might change, based on the health status code.

During reboot, for each incremental package, if it is not fully loaded,
the package manager service will register a health status listener to
continue monitor the health status of this package.

Test: unit test
Test: manual
BUG: 170435166
Change-Id: I220f230c523cfaf2c96019f9478554665e6af486
parent 5c2ad1c9
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -144,4 +144,14 @@ interface IIncrementalService {
     * 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);
}
+8 −2
Original line number Diff line number Diff line
@@ -26,9 +26,15 @@ oneway interface IStorageHealthListener {
    /** 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);
+35 −2
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ public final class IncrementalManager {
                return;
            }
            mLoadingProgressCallbacks.cleanUpCallbacks(storage);
            unregisterHealthListener(codePath);
            mService.deleteStorage(storage.getId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -297,7 +298,7 @@ public final class IncrementalManager {
     * @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 @@ public final class IncrementalManager {
     * @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 @@ public final class IncrementalManager {
        }
    }

    /**
     * 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);
+27 −0
Original line number Diff line number Diff line
@@ -545,4 +545,31 @@ public final class IncrementalStorage {
            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;
        }
    }
}
+23 −72
Original line number Diff line number Diff line
@@ -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 @@ import java.util.function.BiConsumer;
 *
 * 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 @@ public final class IncrementalStates {
    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 @@ public final class IncrementalStates {
        }
    }

    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 @@ public final class IncrementalStates {
                    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 @@ public final class IncrementalStates {
            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 @@ public final class IncrementalStates {
        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 @@ public final class IncrementalStates {
                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 @@ public final class IncrementalStates {
        }
        IncrementalStates l = (IncrementalStates) o;
        return l.mStorageHealthStatus == mStorageHealthStatus
                && l.mStreamStatus == mStreamStatus
                && l.mStartableState.equals(mStartableState)
                && l.mLoadingState.equals(mLoadingState);
    }
@@ -474,7 +426,6 @@ public final class IncrementalStates {
        int hashCode = mStartableState.hashCode();
        hashCode = 31 * hashCode + mLoadingState.hashCode();
        hashCode = 31 * hashCode + mStorageHealthStatus;
        hashCode = 31 * hashCode + mStreamStatus;
        return hashCode;
    }
}
Loading