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

Commit b8b2a386 authored by Winson Chiu's avatar Winson Chiu Committed by Android (Google) Code Review
Browse files

Merge "Remove IncrementalStates in favor of float for progress"

parents 60c2781c d7004f34
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -37,7 +37,20 @@ final class IncrementalProgressListener extends IPackageLoadingProgressCallback.
            if (ps == null) {
                return;
            }

            boolean wasLoading = ps.isPackageLoading();
            // Due to asynchronous progress reporting, incomplete progress might be received
            // after the app is migrated off incremental. Ignore such progress updates.
            if (wasLoading) {
                ps.setLoadingProgress(progress);
                // Only report the state change when loading state changes from loading to not
                if (!ps.isPackageLoading()) {
                    // Unregister progress listener
                    mPm.mIncrementalManager.unregisterLoadingProgressCallbacks(ps.getPathString());
                    // Make sure the information is preserved
                    mPm.scheduleWriteSettingsLocked();
                }
            }
        }
    }
}
+0 −232
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.content.pm.IncrementalStatesInfo;
import android.os.Handler;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;

/**
 * Manages state transitions of a package installed on Incremental File System. Currently manages:
 * 1. loading state (whether a package is still loading or has been fully loaded).
 *
 * The following events might change the states of a package:
 * 1. Installation commit
 * 2. Loading progress changes
 *
 * @hide
 */
public final class IncrementalStates {
    private static final String TAG = "IncrementalStates";
    private static final boolean DEBUG = false;
    private final Handler mHandler = BackgroundThread.getHandler();
    private final Object mLock = new Object();
    @GuardedBy("mLock")
    private final LoadingState mLoadingState;
    @GuardedBy("mLock")
    private Callback mCallback = null;

    public IncrementalStates() {
        // By default the package is not fully loaded (i.e., is loading)
        this(true, 0);
    }

    public IncrementalStates(boolean isLoading, float loadingProgress) {
        mLoadingState = new LoadingState(isLoading, loadingProgress);
    }

    /**
     * Callback interface to report that the loading state of this package has changed.
     */
    public interface Callback {
        /**
         * Reports that package is fully loaded.
         */
        void onPackageFullyLoaded();
    }

    /**
     * By calling this method, the caller indicates that package installation has just been
     * committed. Set the initial loading state after the package
     * is committed. Incremental packages are by-default loading; non-Incremental packages are not.
     *
     * @param isIncremental whether a package is installed on Incremental or not.
     */
    public void onCommit(boolean isIncremental) {
        if (DEBUG) {
            Slog.i(TAG, "received package commit event");
        }
        if (!isIncremental) {
            synchronized (mLock) {
                updateProgressLocked(1.0f);
            }
            onLoadingStateChanged();
        }
    }

    private void onLoadingStateChanged() {
        mHandler.post(PooledLambda.obtainRunnable(
                IncrementalStates::reportFullyLoaded,
                IncrementalStates.this).recycleOnUse());
    }

    private void reportFullyLoaded() {
        final Callback callback;
        synchronized (mLock) {
            callback = mCallback;
        }
        if (callback != null) {
            callback.onPackageFullyLoaded();
        }
    }

    /**
     * Use the specified callback to report state changing events.
     *
     * @param callback Object to report new state.
     */
    public void setCallback(Callback callback) {
        if (DEBUG) {
            Slog.i(TAG, "registered callback");
        }
        synchronized (mLock) {
            mCallback = callback;
        }
    }

    /**
     * Update the package loading progress to specified value.
     *
     * @param progress Value between [0, 1].
     */
    public void setProgress(float progress) {
        final boolean oldLoadingState;
        final boolean newLoadingState;
        synchronized (mLock) {
            oldLoadingState = mLoadingState.isLoading();
            if (oldLoadingState) {
                // Due to asynchronous progress reporting, incomplete progress might be received
                // after the app is migrated off incremental. Ignore such progress updates.
                updateProgressLocked(progress);
            }
            newLoadingState = mLoadingState.isLoading();
        }
        if (oldLoadingState && !newLoadingState) {
            // Only report the state change when loading state changes from true to false
            onLoadingStateChanged();
        }
    }

    /**
     * @return all current states in a Parcelable.
     */
    public IncrementalStatesInfo getIncrementalStatesInfo() {
        synchronized (mLock) {
            return new IncrementalStatesInfo(
                    mLoadingState.isLoading(),
                    mLoadingState.getProgress());
        }
    }

    private void updateProgressLocked(float progress) {
        if (DEBUG) {
            Slog.i(TAG, "received progress update: " + progress);
        }
        mLoadingState.setProgress(progress);
        if (Math.abs(1.0f - progress) < 0.00000001f) {
            if (DEBUG) {
                Slog.i(TAG, "package is fully loaded");
            }
            mLoadingState.setProgress(1.0f);
            if (mLoadingState.isLoading()) {
                mLoadingState.adoptNewLoadingStateLocked(false);
            }
        }
    }

    private class LoadingState {
        private boolean mIsLoading;
        private float mProgress;

        LoadingState(boolean isLoading, float loadingProgress) {
            mIsLoading = isLoading;
            // loading progress is reset to 1 if loading has finished
            mProgress = isLoading ? loadingProgress : 1;
        }

        public boolean isLoading() {
            return mIsLoading;
        }

        public float getProgress() {
            return mProgress;
        }

        public void setProgress(float progress) {
            mProgress = progress;
        }

        public void adoptNewLoadingStateLocked(boolean nextState) {
            if (DEBUG) {
                Slog.i(TAG, "Loading state changed from " + mIsLoading + " to " + nextState);
            }
            mIsLoading = nextState;
        }

        @Override
        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }
            if (!(o instanceof LoadingState)) {
                return false;
            }
            LoadingState l = (LoadingState) o;
            return l.mIsLoading == mIsLoading && l.mProgress == mProgress;
        }

        @Override
        public int hashCode() {
            int hashCode = Boolean.hashCode(mIsLoading);
            hashCode = 31 * hashCode + Float.hashCode(mProgress);
            return hashCode;
        }
    }



    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof IncrementalStates)) {
            return false;
        }
        IncrementalStates l = (IncrementalStates) o;
        return l.mLoadingState.equals(mLoadingState);
    }

    @Override
    public int hashCode() {
        return mLoadingState.hashCode();
    }
}
+0 −46
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

/**
 * Package states callback, used to listen for package state changes and send broadcasts
 */
final class IncrementalStatesCallback implements IncrementalStates.Callback {
    private final String mPackageName;
    private final PackageManagerService mPm;

    IncrementalStatesCallback(String packageName, PackageManagerService pm) {
        mPackageName = packageName;
        mPm = pm;
    }

    @Override
    public void onPackageFullyLoaded() {
        final String codePath;
        synchronized (mPm.mLock) {
            final PackageSetting ps = mPm.mSettings.getPackageLPr(mPackageName);
            if (ps == null) {
                return;
            }
            codePath = ps.getPathString();
        }
        // Unregister progress listener
        mPm.mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
        // Make sure the information is preserved
        mPm.scheduleWriteSettingsLocked();
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.IncrementalManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -455,7 +456,10 @@ final class InstallPackageHelper {
        if (pkgSetting.getInstantApp(userId)) {
            mPm.mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.getAppId());
        }
        pkgSetting.setStatesOnCommit();

        if (!IncrementalManager.isIncrementalPath(pkgSetting.getPathString())) {
            pkgSetting.setLoadingProgress(1f);
        }

        return pkg;
    }
+0 −3
Original line number Diff line number Diff line
@@ -1781,9 +1781,6 @@ final class InstallParams extends HandlerParams {
                final String codePath = ps.getPathString();
                if (IncrementalManager.isIncrementalPath(codePath)
                        && mPm.mIncrementalManager != null) {
                    final IncrementalStatesCallback incrementalStatesCallback =
                            new IncrementalStatesCallback(ps.getPackageName(), mPm);
                    ps.setIncrementalStatesCallback(incrementalStatesCallback);
                    mPm.mIncrementalManager.registerLoadingProgressCallback(codePath,
                            new IncrementalProgressListener(ps.getPackageName(), mPm));
                }
Loading