/* * Copyright (C) 2023 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.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * A service module such as MediaSessionService, VOIP, Camera, Microphone, Location can ask * ActivityManagerService to start a foreground service delegate on behalf of the actual app, * by which the client app's process state can be promoted to FOREGROUND_SERVICE process state which * is higher than the app's actual process state if the app is in the background. This can help to * keep the app in the memory and extra run-time. * The app does not need to define an actual service component nor add it into manifest file. * * @hide */ public class ForegroundServiceDelegationOptions { public static final int DELEGATION_SERVICE_DEFAULT = 0; public static final int DELEGATION_SERVICE_DATA_SYNC = 1; public static final int DELEGATION_SERVICE_MEDIA_PLAYBACK = 2; public static final int DELEGATION_SERVICE_PHONE_CALL = 3; public static final int DELEGATION_SERVICE_LOCATION = 4; public static final int DELEGATION_SERVICE_CONNECTED_DEVICE = 5; public static final int DELEGATION_SERVICE_MEDIA_PROJECTION = 6; public static final int DELEGATION_SERVICE_CAMERA = 7; public static final int DELEGATION_SERVICE_MICROPHONE = 8; public static final int DELEGATION_SERVICE_HEALTH = 9; public static final int DELEGATION_SERVICE_REMOTE_MESSAGING = 10; public static final int DELEGATION_SERVICE_SYSTEM_EXEMPTED = 11; public static final int DELEGATION_SERVICE_SPECIAL_USE = 12; @IntDef(flag = false, prefix = { "DELEGATION_SERVICE_" }, value = { DELEGATION_SERVICE_DEFAULT, DELEGATION_SERVICE_DATA_SYNC, DELEGATION_SERVICE_MEDIA_PLAYBACK, DELEGATION_SERVICE_PHONE_CALL, DELEGATION_SERVICE_LOCATION, DELEGATION_SERVICE_CONNECTED_DEVICE, DELEGATION_SERVICE_MEDIA_PROJECTION, DELEGATION_SERVICE_CAMERA, DELEGATION_SERVICE_MICROPHONE, DELEGATION_SERVICE_HEALTH, DELEGATION_SERVICE_REMOTE_MESSAGING, DELEGATION_SERVICE_SYSTEM_EXEMPTED, DELEGATION_SERVICE_SPECIAL_USE, }) @Retention(RetentionPolicy.SOURCE) public @interface DelegationService {} // The actual app's PID public final int mClientPid; // The actual app's UID public final int mClientUid; // The actual app's package name @NonNull public final String mClientPackageName; // The actual app's app thread @Nullable public final IApplicationThread mClientAppThread; public final boolean mSticky; // Is it a sticky service // The delegation service's instance name which is to identify the delegate. @NonNull public String mClientInstanceName; // The foreground service types it consists of. public final int mForegroundServiceTypes; /** * The service's name such as MediaSessionService, VOIP, Camera, Microphone, Location. This is * the internal module's name which actually starts the FGS delegate on behalf of the client * app. */ public final @DelegationService int mDelegationService; /** * The optional notification Id of the foreground service delegation. */ public final int mClientNotificationId; /** * The optional notification of the foreground service delegation. */ public final @Nullable Notification mClientNotification; public ForegroundServiceDelegationOptions(int clientPid, int clientUid, @NonNull String clientPackageName, @NonNull IApplicationThread clientAppThread, boolean isSticky, @NonNull String clientInstanceName, int foregroundServiceTypes, @DelegationService int delegationService) { this(clientPid, clientUid, clientPackageName, clientAppThread, isSticky, clientInstanceName, foregroundServiceTypes, delegationService, 0 /* notificationId */, null /* notification */); } public 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) { mClientPid = clientPid; mClientUid = clientUid; mClientPackageName = clientPackageName; mClientAppThread = clientAppThread; mSticky = isSticky; mClientInstanceName = clientInstanceName; mForegroundServiceTypes = foregroundServiceTypes; mDelegationService = delegationService; mClientNotificationId = clientNotificationId; mClientNotification = clientNotification; } /** * A service delegates a foreground service state to a clientUID using a instanceName. * This delegation is uniquely identified by * mDelegationService/mClientUid/mClientPid/mClientInstanceName */ public boolean isSameDelegate(ForegroundServiceDelegationOptions that) { return this.mDelegationService == that.mDelegationService && this.mClientUid == that.mClientUid && this.mClientPid == that.mClientPid && this.mClientInstanceName.equals(that.mClientInstanceName); } /** * Construct a component name for this delegate. */ public ComponentName getComponentName() { return new ComponentName(mClientPackageName, serviceCodeToString(mDelegationService) + ":" + mClientInstanceName); } /** * Get string description of this delegate options. */ public String getDescription() { StringBuilder sb = new StringBuilder(128); sb.append("ForegroundServiceDelegate{") .append("package:") .append(mClientPackageName) .append(",") .append("service:") .append(serviceCodeToString(mDelegationService)) .append(",") .append("uid:") .append(mClientUid) .append(",") .append("pid:") .append(mClientPid) .append(",") .append("instance:") .append(mClientInstanceName) .append("}"); return sb.toString(); } /** * Map the integer service code to string name. * @param serviceCode * @return */ public static String serviceCodeToString(@DelegationService int serviceCode) { switch (serviceCode) { case DELEGATION_SERVICE_DEFAULT: return "DEFAULT"; case DELEGATION_SERVICE_DATA_SYNC: return "DATA_SYNC"; case DELEGATION_SERVICE_MEDIA_PLAYBACK: return "MEDIA_PLAYBACK"; case DELEGATION_SERVICE_PHONE_CALL: return "PHONE_CALL"; case DELEGATION_SERVICE_LOCATION: return "LOCATION"; case DELEGATION_SERVICE_CONNECTED_DEVICE: return "CONNECTED_DEVICE"; case DELEGATION_SERVICE_MEDIA_PROJECTION: return "MEDIA_PROJECTION"; case DELEGATION_SERVICE_CAMERA: return "CAMERA"; case DELEGATION_SERVICE_MICROPHONE: return "MICROPHONE"; case DELEGATION_SERVICE_HEALTH: return "HEALTH"; case DELEGATION_SERVICE_REMOTE_MESSAGING: return "REMOTE_MESSAGING"; case DELEGATION_SERVICE_SYSTEM_EXEMPTED: return "SYSTEM_EXEMPTED"; case DELEGATION_SERVICE_SPECIAL_USE: return "SPECIAL_USE"; default: return "(unknown:" + serviceCode + ")"; } } /** * The helper class to build the instance of {@link ForegroundServiceDelegate}. * * @hide */ public static class Builder { int mClientPid; // The actual app PID int mClientUid; // The actual app UID String mClientPackageName; // The actual app's package name int mClientNotificationId; // The actual app's notification id Notification mClientNotification; // The actual app's notification IApplicationThread mClientAppThread; // The actual app's app thread boolean mSticky; // Is it a sticky service String mClientInstanceName; // The delegation service instance name int mForegroundServiceTypes; // The foreground service types it consists of @DelegationService int mDelegationService; // The internal service's name, i.e. VOIP /** * Set the client app's PID. */ public Builder setClientPid(int clientPid) { mClientPid = clientPid; return this; } /** * Set the client app's UID. */ public Builder setClientUid(int clientUid) { mClientUid = clientUid; return this; } /** * Set the client app's package name. */ public Builder setClientPackageName(@NonNull String clientPackageName) { mClientPackageName = clientPackageName; return this; } /** * Set the notification from the client app. */ public Builder setClientNotification(int clientNotificationId, @Nullable Notification clientNotification) { mClientNotificationId = clientNotificationId; mClientNotification = clientNotification; return this; } /** * Set the client app's application thread. */ public Builder setClientAppThread(@NonNull IApplicationThread clientAppThread) { mClientAppThread = clientAppThread; return this; } /** * Set the client instance of this service. */ public Builder setClientInstanceName(@NonNull String clientInstanceName) { mClientInstanceName = clientInstanceName; return this; } /** * Set stickiness of this service. */ public Builder setSticky(boolean isSticky) { mSticky = isSticky; return this; } /** * Set the foreground service type. */ public Builder setForegroundServiceTypes(int foregroundServiceTypes) { mForegroundServiceTypes = foregroundServiceTypes; return this; } /** * Set the delegation service type. */ public Builder setDelegationService(@DelegationService int delegationService) { mDelegationService = delegationService; return this; } /** * @return An instance of {@link ForegroundServiceDelegationOptions}. */ public ForegroundServiceDelegationOptions build() { return new ForegroundServiceDelegationOptions(mClientPid, mClientUid, mClientPackageName, mClientAppThread, mSticky, mClientInstanceName, mForegroundServiceTypes, mDelegationService, mClientNotificationId, mClientNotification ); } } }