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

Commit 771287be authored by George Chan's avatar George Chan
Browse files

Implemented push API for a more performant method to fetch BIC apps.

For more info: go/bic-v

Test: atest BackgroundInstallControlServiceHostTest BackgroundInstallControlServiceTest BackgroundInstallControlCallbackHelperTest
Bug: 323595069
Change-Id: I531c2d96ecc8fbc98e7092864c45ce9be8aff5de
parent 0505c363
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -17,10 +17,15 @@
package android.content.pm;

import android.content.pm.ParceledListSlice;
import android.os.IRemoteCallback;

/**
 * {@hide}
 */
interface IBackgroundInstallControlService {
    ParceledListSlice getBackgroundInstalledPackages(long flags, int userId);

    void registerBackgroundInstallCallback(IRemoteCallback callback);

    void unregisterBackgroundInstallCallback(IRemoteCallback callback);
}
+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 static android.os.Process.THREAD_PRIORITY_BACKGROUND;

import android.annotation.NonNull;
import android.app.BackgroundInstallControlManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IRemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.ServiceThread;

public class BackgroundInstallControlCallbackHelper {

    @VisibleForTesting static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
    @VisibleForTesting static final String FLAGGED_USER_ID_KEY = "userId";
    private static final String TAG = "BackgroundInstallControlCallbackHelper";

    private final Handler mHandler;

    BackgroundInstallControlCallbackHelper() {
        HandlerThread backgroundThread =
                new ServiceThread(
                        "BackgroundInstallControlCallbackHelperBg",
                        THREAD_PRIORITY_BACKGROUND,
                        true);
        backgroundThread.start();
        mHandler = new Handler(backgroundThread.getLooper());
    }

    @NonNull @VisibleForTesting
    final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<>();

    /** Registers callback that gets invoked upon detection of an MBA
     *
     * NOTE: The callback is user context agnostic and currently broadcasts to all users of other
     * users app installs. This is fine because the API is for SystemServer use only.
     */
    public void registerBackgroundInstallCallback(IRemoteCallback callback) {
        synchronized (mCallbacks) {
            mCallbacks.register(callback, null);
        }
    }

    /** Unregisters callback */
    public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
        synchronized (mCallbacks) {
            mCallbacks.unregister(callback);
        }
    }

    /**
     * Invokes all registered callbacks Callbacks are processed through user provided-threads and
     * parameters are passed in via {@link BackgroundInstallControlManager} InstallEvent
     */
    public void notifyAllCallbacks(int userId, String packageName) {
        Bundle extras = new Bundle();
        extras.putCharSequence(FLAGGED_PACKAGE_NAME_KEY, packageName);
        extras.putInt(FLAGGED_USER_ID_KEY, userId);
        synchronized (mCallbacks) {
            mHandler.post(
                    () ->
                            mCallbacks.broadcast(
                                    callback -> {
                                        try {
                                            callback.sendResult(extras);
                                        } catch (RemoteException e) {
                                            Slog.e(
                                                    TAG,
                                                    "error detected: " + e.getLocalizedMessage(),
                                                    e);
                                        }
                                    }));
        }
    }
}
+22 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
@@ -93,6 +94,8 @@ public class BackgroundInstallControlService extends SystemService {
    private final File mDiskFile;
    private final Context mContext;

    private final BackgroundInstallControlCallbackHelper mCallbackHelper;

    private SparseSetArray<String> mBackgroundInstalledPackages = null;

    // User ID -> package name -> set of foreground time frame
@@ -112,6 +115,7 @@ public class BackgroundInstallControlService extends SystemService {
        mHandler = new EventHandler(injector.getLooper(), this);
        mDiskFile = injector.getDiskFile();
        mContext = injector.getContext();
        mCallbackHelper = injector.getBackgroundInstallControlCallbackHelper();
        UsageStatsManagerInternal usageStatsManagerInternal =
                injector.getUsageStatsManagerInternal();
        usageStatsManagerInternal.registerListener(
@@ -150,6 +154,16 @@ public class BackgroundInstallControlService extends SystemService {
            }
        }

        @Override
        public void registerBackgroundInstallCallback(IRemoteCallback callback) {
            mService.mCallbackHelper.registerBackgroundInstallCallback(callback);
        }

        @Override
        public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
            mService.mCallbackHelper.unregisterBackgroundInstallCallback(callback);
        }

    }

    @RequiresPermission(GET_BACKGROUND_INSTALLED_PACKAGES)
@@ -274,6 +288,7 @@ public class BackgroundInstallControlService extends SystemService {

        initBackgroundInstalledPackages();
        mBackgroundInstalledPackages.add(userId, packageName);
        mCallbackHelper.notifyAllCallbacks(userId, packageName);
        writeBackgroundInstalledPackagesToDisk();
    }

@@ -568,6 +583,8 @@ public class BackgroundInstallControlService extends SystemService {

        File getDiskFile();

        BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper();

    }

    private static final class InjectorImpl implements Injector {
@@ -617,5 +634,10 @@ public class BackgroundInstallControlService extends SystemService {
            File file = new File(dir, DISK_FILE_NAME);
            return file;
        }

        @Override
        public BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper() {
            return new BackgroundInstallControlCallbackHelper();
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ java_test_host {
        ":BackgroundInstallControlServiceTestApp",
        ":BackgroundInstallControlMockApp1",
        ":BackgroundInstallControlMockApp2",
        ":BackgroundInstallControlMockApp3",
    ],
    test_suites: [
        "general-tests",
+3 −0
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@
        <option name="push-file"
                key="BackgroundInstallControlMockApp2.apk"
                value="/data/local/tmp/BackgroundInstallControlMockApp2.apk" />
        <option name="push-file"
            key="BackgroundInstallControlMockApp3.apk"
            value="/data/local/tmp/BackgroundInstallControlMockApp3.apk" />
    </target_preparer>

    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
Loading