| /* |
| * 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.app; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.os.IBinder; |
| |
| import com.android.internal.util.Preconditions; |
| |
| import java.util.List; |
| |
| /** |
| * Privileges granted to a Process that allows it to execute starts from the background. |
| * @hide |
| */ |
| public class BackgroundStartPrivileges { |
| /** No privileges. */ |
| public static final BackgroundStartPrivileges NONE = new BackgroundStartPrivileges( |
| false, false, null); |
| /** Allow activity starts (and implies allowing foreground service starts). */ |
| public static final BackgroundStartPrivileges ALLOW_BAL = new BackgroundStartPrivileges( |
| true, true, null); |
| /** Allow foreground service starts. */ |
| public static final BackgroundStartPrivileges ALLOW_FGS = new BackgroundStartPrivileges( |
| false, true, null); |
| |
| private final boolean mAllowsBackgroundActivityStarts; |
| private final boolean mAllowsBackgroundForegroundServiceStarts; |
| private final IBinder mOriginatingToken; |
| |
| private BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts, |
| boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken) { |
| Preconditions.checkArgument( |
| !allowsBackgroundActivityStarts || allowsBackgroundForegroundServiceStarts, |
| "backgroundActivityStarts implies bgFgServiceStarts"); |
| mAllowsBackgroundActivityStarts = allowsBackgroundActivityStarts; |
| mAllowsBackgroundForegroundServiceStarts = allowsBackgroundForegroundServiceStarts; |
| mOriginatingToken = originatingToken; |
| } |
| |
| /** |
| * Return a token that allows background activity starts and attributes it to a specific |
| * originatingToken. |
| */ |
| public static BackgroundStartPrivileges allowBackgroundActivityStarts( |
| @Nullable IBinder originatingToken) { |
| if (originatingToken == null) { |
| // try to avoid creating new instances |
| return ALLOW_BAL; |
| } |
| return new BackgroundStartPrivileges(true, true, originatingToken); |
| } |
| |
| /** |
| * Merge this {@link BackgroundStartPrivileges} with another {@link BackgroundStartPrivileges}. |
| * |
| * The resulting object will grant the union of the privileges of the merged objects. |
| * The originating tokens is retained only if both {@link BackgroundStartPrivileges} are the |
| * same. |
| * |
| * If one of the merged objects is {@link #NONE} then the other object is returned and the |
| * originating token is NOT cleared. |
| */ |
| public @NonNull BackgroundStartPrivileges merge(@Nullable BackgroundStartPrivileges other) { |
| // shortcuts in case |
| if (other == NONE || other == null) { |
| return this; |
| } |
| if (this == NONE) { |
| return other; |
| } |
| |
| boolean allowsBackgroundActivityStarts = |
| this.allowsBackgroundActivityStarts() || other.allowsBackgroundActivityStarts(); |
| boolean allowsBackgroundFgsStarts = |
| this.allowsBackgroundFgsStarts() || other.allowsBackgroundFgsStarts(); |
| if (this.mOriginatingToken == other.mOriginatingToken) { |
| // can reuse this? |
| if (this.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts |
| && this.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) { |
| return this; |
| } |
| // can reuse other? |
| if (other.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts |
| && other.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) { |
| return other; |
| } |
| // need to create a new instance (this should never happen) |
| return new BackgroundStartPrivileges(allowsBackgroundActivityStarts, |
| allowsBackgroundFgsStarts, this.mOriginatingToken); |
| } else { |
| // no originating token -> can use standard instance |
| if (allowsBackgroundActivityStarts) { |
| return ALLOW_BAL; |
| } else if (allowsBackgroundFgsStarts) { |
| return ALLOW_FGS; |
| } else { |
| return NONE; |
| } |
| } |
| } |
| |
| /** |
| * Merge a collection of {@link BackgroundStartPrivileges} into a single token. |
| * |
| * The resulting object will grant the union of the privileges of the merged objects. |
| * The originating tokens is retained only if all {@link BackgroundStartPrivileges} are the |
| * same. |
| * |
| * If the list contains {@link #NONE}s these are ignored. |
| */ |
| public static @NonNull BackgroundStartPrivileges merge( |
| @Nullable List<BackgroundStartPrivileges> list) { |
| if (list == null || list.isEmpty()) { |
| return NONE; |
| } |
| BackgroundStartPrivileges current = list.get(0); |
| for (int i = list.size(); i-- > 1; ) { |
| current = current.merge(list.get(i)); |
| } |
| return current; |
| } |
| |
| /** |
| * @return {@code true} if this grants the permission to start background activities from the |
| * background. |
| */ |
| public boolean allowsBackgroundActivityStarts() { |
| return mAllowsBackgroundActivityStarts; |
| } |
| |
| /** |
| * @return {@code true} this grants the permission to start foreground services from the |
| * background. */ |
| public boolean allowsBackgroundFgsStarts() { |
| return mAllowsBackgroundForegroundServiceStarts; |
| } |
| |
| /** @return true if this grants any privileges. */ |
| public boolean allowsAny() { |
| return mAllowsBackgroundActivityStarts || mAllowsBackgroundForegroundServiceStarts; |
| } |
| |
| /** Return true if this grants no privileges. */ |
| public boolean allowsNothing() { |
| return !allowsAny(); |
| } |
| |
| /** |
| * Gets the originating token. |
| * |
| * The originating token is optional information that allows to trace back the origin of this |
| * object. Besides debugging, this is used to e.g. identify privileges created by the |
| * notification service. |
| */ |
| public @Nullable IBinder getOriginatingToken() { |
| return mOriginatingToken; |
| } |
| |
| @Override |
| public String toString() { |
| if (this == ALLOW_BAL) { |
| return "BSP.ALLOW_BAL"; |
| } |
| if (this == ALLOW_FGS) { |
| return "BSP.ALLOW_FGS"; |
| } |
| if (this == NONE) { |
| return "BSP.NONE"; |
| } |
| return "BackgroundStartPrivileges[" |
| + "allowsBackgroundActivityStarts=" + mAllowsBackgroundActivityStarts |
| + ", allowsBackgroundForegroundServiceStarts=" |
| + mAllowsBackgroundForegroundServiceStarts |
| + ", originatingToken=" + mOriginatingToken |
| + ']'; |
| } |
| } |