• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import java.util.Objects;
27 
28 /**
29  * Privileges granted to a Process that allows it to execute starts from the background.
30  * @hide
31  */
32 public final class BackgroundStartPrivileges {
33     /** No privileges. */
34     public static final BackgroundStartPrivileges NONE = new BackgroundStartPrivileges(
35             false, false, null);
36     /** Allow activity starts (and implies allowing foreground service starts).  */
37     public static final BackgroundStartPrivileges ALLOW_BAL = new BackgroundStartPrivileges(
38             true, true, null);
39     /** Allow foreground service starts. */
40     public static final BackgroundStartPrivileges ALLOW_FGS = new BackgroundStartPrivileges(
41             false, true, null);
42 
43     private final boolean mAllowsBackgroundActivityStarts;
44     private final boolean mAllowsBackgroundForegroundServiceStarts;
45     private final IBinder mOriginatingToken;
46 
BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts, boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken)47     private BackgroundStartPrivileges(boolean allowsBackgroundActivityStarts,
48             boolean allowsBackgroundForegroundServiceStarts, @Nullable IBinder originatingToken) {
49         Preconditions.checkArgument(
50                 !allowsBackgroundActivityStarts || allowsBackgroundForegroundServiceStarts,
51                 "backgroundActivityStarts implies bgFgServiceStarts");
52         mAllowsBackgroundActivityStarts = allowsBackgroundActivityStarts;
53         mAllowsBackgroundForegroundServiceStarts = allowsBackgroundForegroundServiceStarts;
54         mOriginatingToken = originatingToken;
55     }
56 
57     /**
58      * Return a token that allows background activity starts and attributes it to a specific
59      * originatingToken.
60      */
allowBackgroundActivityStarts( @ullable IBinder originatingToken)61     public static BackgroundStartPrivileges allowBackgroundActivityStarts(
62             @Nullable IBinder originatingToken) {
63         if (originatingToken == null) {
64             // try to avoid creating new instances
65             return ALLOW_BAL;
66         }
67         return new BackgroundStartPrivileges(true, true, originatingToken);
68     }
69 
70     /**
71      * Merge this {@link BackgroundStartPrivileges} with another {@link BackgroundStartPrivileges}.
72      *
73      * The resulting object will grant the union of the privileges of the merged objects.
74      * The originating tokens is retained only if both {@link BackgroundStartPrivileges} are the
75      * same.
76      *
77      * If one of the merged objects is {@link #NONE} then the other object is returned and the
78      * originating token is NOT cleared.
79      */
merge(@ullable BackgroundStartPrivileges other)80     public @NonNull BackgroundStartPrivileges merge(@Nullable BackgroundStartPrivileges other) {
81         // shortcuts in case
82         if (other == NONE || other == null) {
83             return this;
84         }
85         if (this == NONE) {
86             return other;
87         }
88 
89         boolean allowsBackgroundActivityStarts =
90                 this.allowsBackgroundActivityStarts() || other.allowsBackgroundActivityStarts();
91         boolean allowsBackgroundFgsStarts =
92                 this.allowsBackgroundFgsStarts() || other.allowsBackgroundFgsStarts();
93         if (this.mOriginatingToken == other.mOriginatingToken) {
94             // can reuse this?
95             if (this.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts
96                     && this.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) {
97                 return this;
98             }
99             // can reuse other?
100             if (other.mAllowsBackgroundActivityStarts == allowsBackgroundActivityStarts
101                    && other.mAllowsBackgroundForegroundServiceStarts == allowsBackgroundFgsStarts) {
102                 return other;
103             }
104             // need to create a new instance (this should never happen)
105             return new BackgroundStartPrivileges(allowsBackgroundActivityStarts,
106                     allowsBackgroundFgsStarts, this.mOriginatingToken);
107         } else {
108             // no originating token -> can use standard instance
109             if (allowsBackgroundActivityStarts) {
110                 return ALLOW_BAL;
111             } else if (allowsBackgroundFgsStarts) {
112                 return ALLOW_FGS;
113             } else {
114                 return NONE;
115             }
116         }
117     }
118 
119     /**
120      * Merge a collection of {@link BackgroundStartPrivileges} into a single token.
121      *
122      * The resulting object will grant the union of the privileges of the merged objects.
123      * The originating tokens is retained only if all {@link BackgroundStartPrivileges} are the
124      * same.
125      *
126      * If the list contains {@link #NONE}s these are ignored.
127      */
merge( @ullable List<BackgroundStartPrivileges> list)128     public static @NonNull BackgroundStartPrivileges merge(
129             @Nullable List<BackgroundStartPrivileges> list) {
130         if (list == null || list.isEmpty()) {
131             return NONE;
132         }
133         BackgroundStartPrivileges current = list.get(0);
134         for (int i = list.size(); i-- > 1; ) {
135             current = current.merge(list.get(i));
136         }
137         return current;
138     }
139 
140     /**
141      * @return {@code true} if this grants the permission to start background activities from the
142      * background.
143      */
allowsBackgroundActivityStarts()144     public boolean allowsBackgroundActivityStarts() {
145         return mAllowsBackgroundActivityStarts;
146     }
147 
148     /**
149      * @return {@code true} this grants the permission to start foreground services from the
150      * background. */
allowsBackgroundFgsStarts()151     public boolean allowsBackgroundFgsStarts() {
152         return mAllowsBackgroundForegroundServiceStarts;
153     }
154 
155     /** @return true if this grants any privileges. */
allowsAny()156     public boolean allowsAny() {
157         return mAllowsBackgroundActivityStarts || mAllowsBackgroundForegroundServiceStarts;
158     }
159 
160     /** Return true if this grants no privileges. */
allowsNothing()161     public boolean allowsNothing() {
162         return !allowsAny();
163     }
164 
165     /**
166      * Gets the originating token.
167      *
168      * The originating token is optional information that allows to trace back the origin of this
169      * object. Besides debugging, this is used to e.g. identify privileges created by the
170      * notification service.
171      */
getOriginatingToken()172     public @Nullable IBinder getOriginatingToken() {
173         return mOriginatingToken;
174     }
175 
176     @Override
toString()177     public String toString() {
178         if (this == ALLOW_BAL) {
179             return "BSP.ALLOW_BAL";
180         }
181         if (this == ALLOW_FGS) {
182             return "BSP.ALLOW_FGS";
183         }
184         if (this == NONE) {
185             return "BSP.NONE";
186         }
187         return "BackgroundStartPrivileges["
188                 + "allowsBackgroundActivityStarts=" + mAllowsBackgroundActivityStarts
189                 + ", allowsBackgroundForegroundServiceStarts="
190                 + mAllowsBackgroundForegroundServiceStarts
191                 + ", originatingToken=" + mOriginatingToken
192                 + ']';
193     }
194 
195     @Override
equals(Object o)196     public boolean equals(Object o) {
197         if (this == o) return true;
198         if (o == null || getClass() != o.getClass()) return false;
199         BackgroundStartPrivileges that = (BackgroundStartPrivileges) o;
200         return mAllowsBackgroundActivityStarts == that.mAllowsBackgroundActivityStarts
201                 && mAllowsBackgroundForegroundServiceStarts
202                 == that.mAllowsBackgroundForegroundServiceStarts
203                 && Objects.equals(mOriginatingToken, that.mOriginatingToken);
204     }
205 
206     @Override
hashCode()207     public int hashCode() {
208         return Objects.hash(mAllowsBackgroundActivityStarts,
209                 mAllowsBackgroundForegroundServiceStarts,
210                 mOriginatingToken);
211     }
212 }
213