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 
ForegroundServiceDelegationOptions(int clientPid, int clientUid, @NonNull String clientPackageName, @NonNull IApplicationThread clientAppThread, boolean isSticky, @NonNull String clientInstanceName, int foregroundServiceTypes, @DelegationService int delegationService)95     public ForegroundServiceDelegationOptions(int clientPid,
96             int clientUid,
97             @NonNull String clientPackageName,
98             @NonNull IApplicationThread clientAppThread,
99             boolean isSticky,
100             @NonNull String clientInstanceName,
101             int foregroundServiceTypes,
102             @DelegationService int delegationService) {
103         mClientPid = clientPid;
104         mClientUid = clientUid;
105         mClientPackageName = clientPackageName;
106         mClientAppThread = clientAppThread;
107         mSticky = isSticky;
108         mClientInstanceName = clientInstanceName;
109         mForegroundServiceTypes = foregroundServiceTypes;
110         mDelegationService = delegationService;
111     }
112 
113     /**
114      * A service delegates a foreground service state to a clientUID using a instanceName.
115      * This delegation is uniquely identified by
116      * mDelegationService/mClientUid/mClientPid/mClientInstanceName
117      */
isSameDelegate(ForegroundServiceDelegationOptions that)118     public boolean isSameDelegate(ForegroundServiceDelegationOptions that) {
119         return this.mDelegationService == that.mDelegationService
120                 && this.mClientUid == that.mClientUid
121                 && this.mClientPid == that.mClientPid
122                 && this.mClientInstanceName.equals(that.mClientInstanceName);
123     }
124 
125     /**
126      * Construct a component name for this delegate.
127      */
getComponentName()128     public ComponentName getComponentName() {
129         return new ComponentName(mClientPackageName, serviceCodeToString(mDelegationService)
130                 + ":" + mClientInstanceName);
131     }
132 
133     /**
134      * Get string description of this delegate options.
135      */
getDescription()136     public String getDescription() {
137         StringBuilder sb = new StringBuilder(128);
138         sb.append("ForegroundServiceDelegate{")
139                 .append("package:")
140                 .append(mClientPackageName)
141                 .append(",")
142                 .append("service:")
143                 .append(serviceCodeToString(mDelegationService))
144                 .append(",")
145                 .append("uid:")
146                 .append(mClientUid)
147                 .append(",")
148                 .append("pid:")
149                 .append(mClientPid)
150                 .append(",")
151                 .append("instance:")
152                 .append(mClientInstanceName)
153                 .append("}");
154         return sb.toString();
155     }
156 
157     /**
158      * Map the integer service code to string name.
159      * @param serviceCode
160      * @return
161      */
serviceCodeToString(@elegationService int serviceCode)162     public static String serviceCodeToString(@DelegationService int serviceCode) {
163         switch (serviceCode) {
164             case DELEGATION_SERVICE_DEFAULT:
165                 return "DEFAULT";
166             case DELEGATION_SERVICE_DATA_SYNC:
167                 return "DATA_SYNC";
168             case DELEGATION_SERVICE_MEDIA_PLAYBACK:
169                 return "MEDIA_PLAYBACK";
170             case DELEGATION_SERVICE_PHONE_CALL:
171                 return "PHONE_CALL";
172             case DELEGATION_SERVICE_LOCATION:
173                 return "LOCATION";
174             case DELEGATION_SERVICE_CONNECTED_DEVICE:
175                 return "CONNECTED_DEVICE";
176             case DELEGATION_SERVICE_MEDIA_PROJECTION:
177                 return "MEDIA_PROJECTION";
178             case DELEGATION_SERVICE_CAMERA:
179                 return "CAMERA";
180             case DELEGATION_SERVICE_MICROPHONE:
181                 return "MICROPHONE";
182             case DELEGATION_SERVICE_HEALTH:
183                 return "HEALTH";
184             case DELEGATION_SERVICE_REMOTE_MESSAGING:
185                 return "REMOTE_MESSAGING";
186             case DELEGATION_SERVICE_SYSTEM_EXEMPTED:
187                 return "SYSTEM_EXEMPTED";
188             case DELEGATION_SERVICE_SPECIAL_USE:
189                 return "SPECIAL_USE";
190             default:
191                 return "(unknown:" + serviceCode + ")";
192         }
193     }
194 
195     /**
196      * The helper class to build the instance of {@link ForegroundServiceDelegate}.
197      *
198      * @hide
199      */
200     public static class Builder {
201         int mClientPid; // The actual app PID
202         int mClientUid; // The actual app UID
203         String mClientPackageName; // The actual app's package name
204         int mClientNotificationId; // The actual app's notification
205         IApplicationThread mClientAppThread; // The actual app's app thread
206         boolean mSticky; // Is it a sticky service
207         String mClientInstanceName; // The delegation service instance name
208         int mForegroundServiceTypes; // The foreground service types it consists of
209         @DelegationService int mDelegationService; // The internal service's name, i.e. VOIP
210 
211         /**
212          * Set the client app's PID.
213          */
setClientPid(int clientPid)214         public Builder setClientPid(int clientPid) {
215             mClientPid = clientPid;
216             return this;
217         }
218 
219         /**
220          * Set the client app's UID.
221          */
setClientUid(int clientUid)222         public Builder setClientUid(int clientUid) {
223             mClientUid = clientUid;
224             return this;
225         }
226 
227         /**
228          * Set the client app's package name.
229          */
setClientPackageName(@onNull String clientPackageName)230         public Builder setClientPackageName(@NonNull String clientPackageName) {
231             mClientPackageName = clientPackageName;
232             return this;
233         }
234 
235         /**
236          * Set the notification ID from the client app.
237          */
setClientNotificationId(int clientNotificationId)238         public Builder setClientNotificationId(int clientNotificationId) {
239             mClientNotificationId = clientNotificationId;
240             return this;
241         }
242 
243         /**
244          * Set the client app's application thread.
245          */
setClientAppThread(@onNull IApplicationThread clientAppThread)246         public Builder setClientAppThread(@NonNull IApplicationThread clientAppThread) {
247             mClientAppThread = clientAppThread;
248             return this;
249         }
250 
251         /**
252          * Set the client instance of this service.
253          */
setClientInstanceName(@onNull String clientInstanceName)254         public Builder setClientInstanceName(@NonNull String clientInstanceName) {
255             mClientInstanceName = clientInstanceName;
256             return this;
257         }
258 
259         /**
260          * Set stickiness of this service.
261          */
setSticky(boolean isSticky)262         public Builder setSticky(boolean isSticky) {
263             mSticky = isSticky;
264             return this;
265         }
266 
267         /**
268          * Set the foreground service type.
269          */
setForegroundServiceTypes(int foregroundServiceTypes)270         public Builder setForegroundServiceTypes(int foregroundServiceTypes) {
271             mForegroundServiceTypes = foregroundServiceTypes;
272             return this;
273         }
274 
275         /**
276          * Set the delegation service type.
277          */
setDelegationService(@elegationService int delegationService)278         public Builder setDelegationService(@DelegationService int delegationService) {
279             mDelegationService = delegationService;
280             return this;
281         }
282 
283         /**
284          * @return An instance of {@link ForegroundServiceDelegationOptions}.
285          */
build()286         public ForegroundServiceDelegationOptions build() {
287             return new ForegroundServiceDelegationOptions(mClientPid,
288                 mClientUid,
289                 mClientPackageName,
290                 mClientAppThread,
291                 mSticky,
292                 mClientInstanceName,
293                 mForegroundServiceTypes,
294                 mDelegationService
295             );
296         }
297     }
298 }
299