diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d65210b8a0bc9..a0332a15c8dd5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5193,6 +5193,15 @@ public abstract class Context { */ public static final String DROPBOX_SERVICE = "dropbox"; + /** + * System service name for BackgroundInstallControlService. This service supervises the MBAs + * on device and provides the related metadata of the MBAs. + * + * @hide + */ + @SuppressLint("ServiceName") + public static final String BACKGROUND_INSTALL_CONTROL_SERVICE = "background_install_control"; + /** * System service name for BinaryTransparencyService. This is used to retrieve measurements * pertaining to various pre-installed and system binaries on device for the purposes of diff --git a/core/java/android/content/pm/IBackgroundInstallControlService.aidl b/core/java/android/content/pm/IBackgroundInstallControlService.aidl new file mode 100644 index 0000000000000..c8e7caebc8212 --- /dev/null +++ b/core/java/android/content/pm/IBackgroundInstallControlService.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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 android.content.pm; + +import android.content.pm.ParceledListSlice; + +/** + * {@hide} + */ +interface IBackgroundInstallControlService { + ParceledListSlice getBackgroundInstalledPackages(long flags, int userId); +} diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java new file mode 100644 index 0000000000000..df95f86d1e079 --- /dev/null +++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 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.annotation.NonNull; +import android.content.Context; +import android.content.pm.IBackgroundInstallControlService; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.SparseArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemService; + +/** + * @hide + */ +public class BackgroundInstallControlService extends SystemService { + private static final String TAG = "BackgroundInstallControlService"; + + private final Context mContext; + private final BinderService mBinderService; + private final IPackageManager mIPackageManager; + + // User ID -> package name -> time diff + // The time diff between the last foreground activity installer and + // the "onPackageAdded" function call. + private final SparseArrayMap mBackgroundInstalledPackages = + new SparseArrayMap<>(); + + public BackgroundInstallControlService(@NonNull Context context) { + this(new InjectorImpl(context)); + } + + @VisibleForTesting + BackgroundInstallControlService(@NonNull Injector injector) { + super(injector.getContext()); + mContext = injector.getContext(); + mIPackageManager = injector.getIPackageManager(); + mBinderService = new BinderService(this); + } + + private static final class BinderService extends IBackgroundInstallControlService.Stub { + final BackgroundInstallControlService mService; + + BinderService(BackgroundInstallControlService service) { + mService = service; + } + + @Override + public ParceledListSlice getBackgroundInstalledPackages( + @PackageManager.PackageInfoFlagsBits long flags, int userId) { + ParceledListSlice packages; + try { + packages = mService.mIPackageManager.getInstalledPackages(flags, userId); + } catch (RemoteException e) { + throw new IllegalStateException("Package manager not available", e); + } + + // TODO(b/244216300): to enable the test the usage by BinaryTransparencyService, + // we currently comment out the actual implementation. + // The fake implementation is just to filter out the first app of the list. + // for (int i = 0, size = packages.getList().size(); i < size; i++) { + // String packageName = packages.getList().get(i).packageName; + // if (!mBackgroundInstalledPackages.contains(userId, packageName) { + // packages.getList().remove(i); + // } + // } + if (packages.getList().size() > 0) { + packages.getList().remove(0); + } + return packages; + } + } + + /** + * Called when the system service should publish a binder service using + * {@link #publishBinderService(String, IBinder).} + */ + @Override + public void onStart() { + publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService); + } + + /** + * Dependency injector for {@link #BackgroundInstallControlService)}. + */ + interface Injector { + Context getContext(); + + IPackageManager getIPackageManager(); + } + + private static final class InjectorImpl implements Injector { + private final Context mContext; + + InjectorImpl(Context context) { + mContext = context; + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public IPackageManager getIPackageManager() { + return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b74fedf3ff462..593e64828ffcf 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -154,6 +154,7 @@ import com.android.server.os.SchedulingPolicyService; import com.android.server.people.PeopleService; import com.android.server.pm.ApexManager; import com.android.server.pm.ApexSystemServiceInfo; +import com.android.server.pm.BackgroundInstallControlService; import com.android.server.pm.CrossProfileAppsService; import com.android.server.pm.DataLoaderManagerService; import com.android.server.pm.DynamicCodeLoggingService; @@ -2469,6 +2470,10 @@ public final class SystemServer implements Dumpable { t.traceBegin("StartMediaMetricsManager"); mSystemServiceManager.startService(MediaMetricsManagerService.class); t.traceEnd(); + + t.traceBegin("StartBackgroundInstallControlService"); + mSystemServiceManager.startService(BackgroundInstallControlService.class); + t.traceEnd(); } t.traceBegin("StartMediaProjectionManager");