1 /*
2  * Copyright (C) 2023 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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.ComponentName;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 
27 /**
28  * A service module such as MediaSessionService, VOIP, Camera, Microphone, Location can ask
29  * ActivityManagerService to start a foreground service delegate on behalf of the actual app,
30  * by which the client app's process state can be promoted to FOREGROUND_SERVICE process state which
31  * is higher than the app's actual process state if the app is in the background. This can help to
32  * keep the app in the memory and extra run-time.
33  * The app does not need to define an actual service component nor add it into manifest file.
34  *
35  * @hide
36  */
37 public class ForegroundServiceDelegationOptions {
38 
39     public static final int DELEGATION_SERVICE_DEFAULT = 0;
40     public static final int DELEGATION_SERVICE_DATA_SYNC = 1;
41     public static final int DELEGATION_SERVICE_MEDIA_PLAYBACK = 2;
42     public static final int DELEGATION_SERVICE_PHONE_CALL = 3;
43     public static final int DELEGATION_SERVICE_LOCATION = 4;
44     public static final int DELEGATION_SERVICE_CONNECTED_DEVICE = 5;
45     public static final int DELEGATION_SERVICE_MEDIA_PROJECTION = 6;
46     public static final int DELEGATION_SERVICE_CAMERA = 7;
47     public static final int DELEGATION_SERVICE_MICROPHONE = 8;
48     public static final int DELEGATION_SERVICE_HEALTH = 9;
49     public static final int DELEGATION_SERVICE_REMOTE_MESSAGING = 10;
50     public static final int DELEGATION_SERVICE_SYSTEM_EXEMPTED = 11;
51     public static final int DELEGATION_SERVICE_SPECIAL_USE = 12;
52 
53     @IntDef(flag = false, prefix = { "DELEGATION_SERVICE_" }, value = {
54             DELEGATION_SERVICE_DEFAULT,
55             DELEGATION_SERVICE_DATA_SYNC,
56             DELEGATION_SERVICE_MEDIA_PLAYBACK,
57             DELEGATION_SERVICE_PHONE_CALL,
58             DELEGATION_SERVICE_LOCATION,
59             DELEGATION_SERVICE_CONNECTED_DEVICE,
60             DELEGATION_SERVICE_MEDIA_PROJECTION,
61             DELEGATION_SERVICE_CAMERA,
62             DELEGATION_SERVICE_MICROPHONE,
63             DELEGATION_SERVICE_HEALTH,
64             DELEGATION_SERVICE_REMOTE_MESSAGING,
65             DELEGATION_SERVICE_SYSTEM_EXEMPTED,
66             DELEGATION_SERVICE_SPECIAL_USE,
67     })
68     @Retention(RetentionPolicy.SOURCE)
69     public @interface DelegationService {}
70 
71     // The actual app's PID
72     public final int mClientPid;
73     // The actual app's UID
74     public final int mClientUid;
75     // The actual app's package name
76     @NonNull
77     public final String mClientPackageName;
78     // The actual app's app thread
79     @Nullable
80     public final IApplicationThread mClientAppThread;
81     public final boolean mSticky; // Is it a sticky service
82 
83     // The delegation service's instance name which is to identify the delegate.
84     @NonNull
85     public String mClientInstanceName;
86     // The foreground service types it consists of.
87     public final int mForegroundServiceTypes;
88     /**
89      * The service's name such as MediaSessionService, VOIP, Camera, Microphone, Location. This is
90      * the internal module's name which actually starts the FGS delegate on behalf of the client
91      * app.
92      */
93     public final @DelegationService int mDelegationService;
94 
95     /**
96      * The optional notification Id of the foreground service delegation.
97      */
98     public final int mClientNotificationId;
99 
100     /**
101      * The optional notification of the foreground service delegation.
102      */
103     public final @Nullable Notification mClientNotification;
104 
ForegroundServiceDelegationOptions(int clientPid, int clientUid, @NonNull String clientPackageName, @NonNull IApplicationThread clientAppThread, boolean isSticky, @NonNull String clientInstanceName, int foregroundServiceTypes, @DelegationService int delegationService)105     public ForegroundServiceDelegationOptions(int clientPid,
106             int clientUid,
107             @NonNull String clientPackageName,
108             @NonNull IApplicationThread clientAppThread,
109             boolean isSticky,
110             @NonNull String clientInstanceName,
111             int foregroundServiceTypes,
112             @DelegationService int delegationService) {
113         this(clientPid, clientUid, clientPackageName, clientAppThread, isSticky,
114                 clientInstanceName, foregroundServiceTypes, delegationService,
115                 0 /* notificationId */, null /* notification */);
116     }
117 
ForegroundServiceDelegationOptions(int clientPid, int clientUid, @NonNull String clientPackageName, @NonNull IApplicationThread clientAppThread, boolean isSticky, @NonNull String clientInstanceName, int foregroundServiceTypes, @DelegationService int delegationService, int clientNotificationId, @Nullable Notification clientNotification)118     public ForegroundServiceDelegationOptions(int clientPid,
119             int clientUid,
120             @NonNull String clientPackageName,
121             @NonNull IApplicationThread clientAppThread,
122             boolean isSticky,
123             @NonNull String clientInstanceName,
124             int foregroundServiceTypes,
125             @DelegationService int delegationService,
126             int clientNotificationId,
127             @Nullable Notification clientNotification) {
128         mClientPid = clientPid;
129         mClientUid = clientUid;
130         mClientPackageName = clientPackageName;
131         mClientAppThread = clientAppThread;
132         mSticky = isSticky;
133         mClientInstanceName = clientInstanceName;
134         mForegroundServiceTypes = foregroundServiceTypes;
135         mDelegationService = delegationService;
136         mClientNotificationId = clientNotificationId;
137         mClientNotification = clientNotification;
138     }
139 
140     /**
141      * A service delegates a foreground service state to a clientUID using a instanceName.
142      * This delegation is uniquely identified by
143      * mDelegationService/mClientUid/mClientPid/mClientInstanceName
144      */
isSameDelegate(ForegroundServiceDelegationOptions that)145     public boolean isSameDelegate(ForegroundServiceDelegationOptions that) {
146         return this.mDelegationService == that.mDelegationService
147                 && this.mClientUid == that.mClientUid
148                 && this.mClientPid == that.mClientPid
149                 && this.mClientInstanceName.equals(that.mClientInstanceName);
150     }
151 
152     /**
153      * Construct a component name for this delegate.
154      */
getComponentName()155     public ComponentName getComponentName() {
156         return new ComponentName(mClientPackageName, serviceCodeToString(mDelegationService)
157                 + ":" + mClientInstanceName);
158     }
159 
160     /**
161      * Get string description of this delegate options.
162      */
getDescription()163     public String getDescription() {
164         StringBuilder sb = new StringBuilder(128);
165         sb.append("ForegroundServiceDelegate{")
166                 .append("package:")
167                 .append(mClientPackageName)
168                 .append(",")
169                 .append("service:")
170                 .append(serviceCodeToString(mDelegationService))
171                 .append(",")
172                 .append("uid:")
173                 .append(mClientUid)
174                 .append(",")
175                 .append("pid:")
176                 .append(mClientPid)
177                 .append(",")
178                 .append("instance:")
179                 .append(mClientInstanceName)
180                 .append("}");
181         return sb.toString();
182     }
183 
184     /**
185      * Map the integer service code to string name.
186      * @param serviceCode
187      * @return
188      */
serviceCodeToString(@elegationService int serviceCode)189     public static String serviceCodeToString(@DelegationService int serviceCode) {
190         switch (serviceCode) {
191             case DELEGATION_SERVICE_DEFAULT:
192                 return "DEFAULT";
193             case DELEGATION_SERVICE_DATA_SYNC:
194                 return "DATA_SYNC";
195             case DELEGATION_SERVICE_MEDIA_PLAYBACK:
196                 return "MEDIA_PLAYBACK";
197             case DELEGATION_SERVICE_PHONE_CALL:
198                 return "PHONE_CALL";
199             case DELEGATION_SERVICE_LOCATION:
200                 return "LOCATION";
201             case DELEGATION_SERVICE_CONNECTED_DEVICE:
202                 return "CONNECTED_DEVICE";
203             case DELEGATION_SERVICE_MEDIA_PROJECTION:
204                 return "MEDIA_PROJECTION";
205             case DELEGATION_SERVICE_CAMERA:
206                 return "CAMERA";
207             case DELEGATION_SERVICE_MICROPHONE:
208                 return "MICROPHONE";
209             case DELEGATION_SERVICE_HEALTH:
210                 return "HEALTH";
211             case DELEGATION_SERVICE_REMOTE_MESSAGING:
212                 return "REMOTE_MESSAGING";
213             case DELEGATION_SERVICE_SYSTEM_EXEMPTED:
214                 return "SYSTEM_EXEMPTED";
215             case DELEGATION_SERVICE_SPECIAL_USE:
216                 return "SPECIAL_USE";
217             default:
218                 return "(unknown:" + serviceCode + ")";
219         }
220     }
221 
222     /**
223      * The helper class to build the instance of {@link ForegroundServiceDelegate}.
224      *
225      * @hide
226      */
227     public static class Builder {
228         int mClientPid; // The actual app PID
229         int mClientUid; // The actual app UID
230         String mClientPackageName; // The actual app's package name
231         int mClientNotificationId; // The actual app's notification id
232         Notification mClientNotification; // The actual app's notification
233         IApplicationThread mClientAppThread; // The actual app's app thread
234         boolean mSticky; // Is it a sticky service
235         String mClientInstanceName; // The delegation service instance name
236         int mForegroundServiceTypes; // The foreground service types it consists of
237         @DelegationService int mDelegationService; // The internal service's name, i.e. VOIP
238 
239         /**
240          * Set the client app's PID.
241          */
setClientPid(int clientPid)242         public Builder setClientPid(int clientPid) {
243             mClientPid = clientPid;
244             return this;
245         }
246 
247         /**
248          * Set the client app's UID.
249          */
setClientUid(int clientUid)250         public Builder setClientUid(int clientUid) {
251             mClientUid = clientUid;
252             return this;
253         }
254 
255         /**
256          * Set the client app's package name.
257          */
setClientPackageName(@onNull String clientPackageName)258         public Builder setClientPackageName(@NonNull String clientPackageName) {
259             mClientPackageName = clientPackageName;
260             return this;
261         }
262 
263         /**
264          * Set the notification from the client app.
265          */
setClientNotification(int clientNotificationId, @Nullable Notification clientNotification)266         public Builder setClientNotification(int clientNotificationId,
267                 @Nullable Notification clientNotification) {
268             mClientNotificationId = clientNotificationId;
269             mClientNotification = clientNotification;
270             return this;
271         }
272 
273         /**
274          * Set the client app's application thread.
275          */
setClientAppThread(@onNull IApplicationThread clientAppThread)276         public Builder setClientAppThread(@NonNull IApplicationThread clientAppThread) {
277             mClientAppThread = clientAppThread;
278             return this;
279         }
280 
281         /**
282          * Set the client instance of this service.
283          */
setClientInstanceName(@onNull String clientInstanceName)284         public Builder setClientInstanceName(@NonNull String clientInstanceName) {
285             mClientInstanceName = clientInstanceName;
286             return this;
287         }
288 
289         /**
290          * Set stickiness of this service.
291          */
setSticky(boolean isSticky)292         public Builder setSticky(boolean isSticky) {
293             mSticky = isSticky;
294             return this;
295         }
296 
297         /**
298          * Set the foreground service type.
299          */
setForegroundServiceTypes(int foregroundServiceTypes)300         public Builder setForegroundServiceTypes(int foregroundServiceTypes) {
301             mForegroundServiceTypes = foregroundServiceTypes;
302             return this;
303         }
304 
305         /**
306          * Set the delegation service type.
307          */
setDelegationService(@elegationService int delegationService)308         public Builder setDelegationService(@DelegationService int delegationService) {
309             mDelegationService = delegationService;
310             return this;
311         }
312 
313         /**
314          * @return An instance of {@link ForegroundServiceDelegationOptions}.
315          */
build()316         public ForegroundServiceDelegationOptions build() {
317             return new ForegroundServiceDelegationOptions(mClientPid,
318                 mClientUid,
319                 mClientPackageName,
320                 mClientAppThread,
321                 mSticky,
322                 mClientInstanceName,
323                 mForegroundServiceTypes,
324                 mDelegationService,
325                 mClientNotificationId,
326                 mClientNotification
327             );
328         }
329     }
330 }
331