1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.IBinder; 22 23 import com.android.internal.util.Preconditions; 24 25 import java.util.List; 26 27 /** 28 * Privileges granted to a Process that allows it to execute starts from the background. 29 * @hide 30 */ 31 public class BackgroundStartPrivileges { 32 /** No privileges. */ 33 public static final BackgroundStartPrivileges NONE = new BackgroundStartPrivileges( 34 false, false, null); 35 /** Allow activity starts (and implies allowing foreground service starts). */ 36 public static final BackgroundStartPrivileges ALLOW_BAL = new BackgroundStartPrivileges( 37 true, true, null); 38 /** Allow foreground service starts. */ 39 public static final BackgroundStartPrivileges ALLOW_FGS = new BackgroundStartPrivileges( 40 false, true, null); 41 42 private final boolean mAllowsBackgroundActivityStarts; 43 private final boolean mAllowsBackgroundForegroundServiceStarts; 44 private final IBinder mOriginatingToken; 45 BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts, boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken)46 private BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts, 47 boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken) { 48 Preconditions.checkArgument( 49 !allowsBackgroundActivityStarts || allowsBackgroundForegroundServiceStarts, 50 "backgroundActivityStarts implies bgFgServiceStarts"); 51 mAllowsBackgroundActivityStarts = allowsBackgroundActivityStarts; 52 mAllowsBackgroundForegroundServiceStarts = allowsBackgroundForegroundServiceStarts; 53 mOriginatingToken = originatingToken; 54 } 55 56 /** 57 * Return a token that allows background activity starts and attributes it to a specific 58 * originatingToken. 59 */ allowBackgroundActivityStarts( @ullable IBinder originatingToken)60 public static BackgroundStartPrivileges allowBackgroundActivityStarts( 61 @Nullable IBinder originatingToken) { 62 if (originatingToken == null) { 63 // try to avoid creating new instances 64 return ALLOW_BAL; 65 } 66 return new BackgroundStartPrivileges(true, true, originatingToken); 67 } 68 69 /** 70 * Merge this {@link BackgroundStartPrivileges} with another {@link BackgroundStartPrivileges}. 71 * 72 * The resulting object will grant the union of the privileges of the merged objects. 73 * The originating tokens is retained only if both {@link BackgroundStartPrivileges} are the 74 * same. 75 * 76 * If one of the merged objects is {@link #NONE} then the other object is returned and the 77 * originating token is NOT cleared. 78 */ merge(@ullable BackgroundStartPrivileges other)79 public @NonNull BackgroundStartPrivileges merge(@Nullable BackgroundStartPrivileges other) { 80 // shortcuts in case 81 if (other == NONE || other == null) { 82 return this; 83 } 84 if (this == NONE) { 85 return other; 86 } 87 88 boolean allowsBackgroundActivityStarts = 89 this.allowsBackgroundActivityStarts() || other.allowsBackgroundActivityStarts(); 90 boolean allowsBackgroundFgsStarts = 91 this.allowsBackgroundFgsStarts() || other.allowsBackgroundFgsStarts(); 92 if (this.mOriginatingToken == other.mOriginatingToken) { 93 // can reuse this? 94 if (this.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts 95 && this.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) { 96 return this; 97 } 98 // can reuse other? 99 if (other.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts 100 && other.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) { 101 return other; 102 } 103 // need to create a new instance (this should never happen) 104 return new BackgroundStartPrivileges(allowsBackgroundActivityStarts, 105 allowsBackgroundFgsStarts, this.mOriginatingToken); 106 } else { 107 // no originating token -> can use standard instance 108 if (allowsBackgroundActivityStarts) { 109 return ALLOW_BAL; 110 } else if (allowsBackgroundFgsStarts) { 111 return ALLOW_FGS; 112 } else { 113 return NONE; 114 } 115 } 116 } 117 118 /** 119 * Merge a collection of {@link BackgroundStartPrivileges} into a single token. 120 * 121 * The resulting object will grant the union of the privileges of the merged objects. 122 * The originating tokens is retained only if all {@link BackgroundStartPrivileges} are the 123 * same. 124 * 125 * If the list contains {@link #NONE}s these are ignored. 126 */ merge( @ullable List<BackgroundStartPrivileges> list)127 public static @NonNull BackgroundStartPrivileges merge( 128 @Nullable List<BackgroundStartPrivileges> list) { 129 if (list == null || list.isEmpty()) { 130 return NONE; 131 } 132 BackgroundStartPrivileges current = list.get(0); 133 for (int i = list.size(); i-- > 1; ) { 134 current = current.merge(list.get(i)); 135 } 136 return current; 137 } 138 139 /** 140 * @return {@code true} if this grants the permission to start background activities from the 141 * background. 142 */ allowsBackgroundActivityStarts()143 public boolean allowsBackgroundActivityStarts() { 144 return mAllowsBackgroundActivityStarts; 145 } 146 147 /** 148 * @return {@code true} this grants the permission to start foreground services from the 149 * background. */ allowsBackgroundFgsStarts()150 public boolean allowsBackgroundFgsStarts() { 151 return mAllowsBackgroundForegroundServiceStarts; 152 } 153 154 /** @return true if this grants any privileges. */ allowsAny()155 public boolean allowsAny() { 156 return mAllowsBackgroundActivityStarts || mAllowsBackgroundForegroundServiceStarts; 157 } 158 159 /** Return true if this grants no privileges. */ allowsNothing()160 public boolean allowsNothing() { 161 return !allowsAny(); 162 } 163 164 /** 165 * Gets the originating token. 166 * 167 * The originating token is optional information that allows to trace back the origin of this 168 * object. Besides debugging, this is used to e.g. identify privileges created by the 169 * notification service. 170 */ getOriginatingToken()171 public @Nullable IBinder getOriginatingToken() { 172 return mOriginatingToken; 173 } 174 175 @Override toString()176 public String toString() { 177 if (this == ALLOW_BAL) { 178 return "BSP.ALLOW_BAL"; 179 } 180 if (this == ALLOW_FGS) { 181 return "BSP.ALLOW_FGS"; 182 } 183 if (this == NONE) { 184 return "BSP.NONE"; 185 } 186 return "BackgroundStartPrivileges[" 187 + "allowsBackgroundActivityStarts=" + mAllowsBackgroundActivityStarts 188 + ", allowsBackgroundForegroundServiceStarts=" 189 + mAllowsBackgroundForegroundServiceStarts 190 + ", originatingToken=" + mOriginatingToken 191 + ']'; 192 } 193 } 194