/* * Copyright (C) 2018 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.admin; import static android.app.admin.DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS; import static android.app.admin.DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE; import static android.app.admin.DeviceAdminReceiver.ACTION_SECURITY_LOGS_AVAILABLE; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID; import static android.app.admin.DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URI; import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT; import static android.app.admin.DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.security.KeyChain; import android.util.Log; /** * Base class for delegated apps to handle callbacks related to their delegated capabilities. * *
Delegated apps are apps that receive additional capabilities from the profile owner or * device owner apps. Some of these capabilities involve the framework calling into the apps. * To receive these callbacks, delegated apps should subclass this class and override the * appropriate methods here. The subclassed receiver needs to be published in the app's * manifest, with appropriate intent filters to mark which callbacks the receiver is interested * in. An app can have multiple receivers as long as they listen for disjoint set of callbacks. * For the manifest definitions, it must be protected by the * {@link android.Manifest.permission#BIND_DEVICE_ADMIN} permission to ensure only * the system can trigger these callbacks. * *
The callback methods happen on the main thread of the process. Thus long running * operations must be done on another thread. Note that because a receiver * is done once returning from its onReceive function, such long-running operations * should probably be done in a {@link Service}. * * @see DevicePolicyManager#setDelegatedScopes * @see DeviceAdminReceiver */ public class DelegatedAdminReceiver extends BroadcastReceiver { private static final String TAG = "DelegatedAdminReceiver"; /** * Allows this receiver to select the alias for a private key and certificate pair for * authentication. If this method returns null, the default {@link android.app.Activity} will * be shown that lets the user pick a private key and certificate pair. * If this method returns {@link KeyChain#KEY_ALIAS_SELECTION_DENIED}, * the default {@link android.app.Activity} will not be shown and the user will not be allowed * to pick anything. And the app, that called {@link KeyChain#choosePrivateKeyAlias}, will * receive {@code null} back. * *
This callback is only applicable if the delegated app has * {@link DevicePolicyManager#DELEGATION_CERT_SELECTION} capability. Additionally, it must * declare an intent filter for {@link DeviceAdminReceiver#ACTION_CHOOSE_PRIVATE_KEY_ALIAS} * in the receiver's manifest in order to receive this callback. The default implementation * simply throws {@link UnsupportedOperationException}. * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. * @param uid The uid of the app asking for the private key and certificate pair. * @param uri The URI to authenticate, may be null. * @param alias The alias preselected by the client, or null. * @return The private key alias to return and grant access to. * @see KeyChain#choosePrivateKeyAlias */ public @Nullable String onChoosePrivateKeyAlias(@NonNull Context context, @NonNull Intent intent, int uid, @Nullable Uri uri, @Nullable String alias) { throw new UnsupportedOperationException("onChoosePrivateKeyAlias should be implemented"); } /** * Called each time a new batch of network logs can be retrieved. This callback method will only * ever be called when network logging is enabled. The logs can only be retrieved while network * logging is enabled. * *
If a secondary user or profile is created, this callback won't be received until all users * become affiliated again (even if network logging is enabled). It will also no longer be * possible to retrieve the network logs batch with the most recent {@code batchToken} provided * by this callback. See {@link DevicePolicyManager#setAffiliationIds}. * *
This callback is only applicable if the delegated app has * {@link DevicePolicyManager#DELEGATION_NETWORK_LOGGING} capability. Additionally, it must * declare an intent filter for {@link DeviceAdminReceiver#ACTION_NETWORK_LOGS_AVAILABLE} in the * receiver's manifest in order to receive this callback. The default implementation * simply throws {@link UnsupportedOperationException}. * *
* This callback is triggered by a foreground broadcast and the app should ensure that any * long-running work is not executed synchronously inside the callback. * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. * @param batchToken The token representing the current batch of network logs. * @param networkLogsCount The total count of events in the current batch of network logs. * @see DevicePolicyManager#retrieveNetworkLogs */ public void onNetworkLogsAvailable(@NonNull Context context, @NonNull Intent intent, long batchToken, @IntRange(from = 1) int networkLogsCount) { throw new UnsupportedOperationException("onNetworkLogsAvailable should be implemented"); } /** * Called each time a new batch of security logs can be retrieved. This callback method will * only ever be called when security logging is enabled. The logs can only be retrieved while * security logging is enabled. * *
If a secondary user or profile is created, this callback won't be received until all users * become affiliated again (even if security logging is enabled). It will also no longer be * possible to retrieve the security logs. See {@link DevicePolicyManager#setAffiliationIds}. * *
This callback is only applicable if the delegated app has * {@link DevicePolicyManager#DELEGATION_SECURITY_LOGGING} capability. Additionally, it must * declare an intent filter for {@link DeviceAdminReceiver#ACTION_SECURITY_LOGS_AVAILABLE} in * the receiver's manifest in order to receive this callback. The default implementation * simply throws {@link UnsupportedOperationException}. * *
* This callback is triggered by a foreground broadcast and the app should ensure that any * long-running work is not executed synchronously inside the callback. * * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. * @see DevicePolicyManager#retrieveSecurityLogs */ public void onSecurityLogsAvailable(@NonNull Context context, @NonNull Intent intent) { throw new UnsupportedOperationException("onSecurityLogsAvailable should be implemented"); } /** * Intercept delegated device administrator broadcasts. Implementations should not override * this method; implement the convenience callbacks for each action instead. */ @Override public final void onReceive(@NonNull Context context, @NonNull Intent intent) { String action = intent.getAction(); if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) { int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1); Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI, android.net.Uri.class); String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS); String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, uri, alias); setResultData(chosenAlias); } else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) { long batchToken = intent.getLongExtra(EXTRA_NETWORK_LOGS_TOKEN, -1); int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0); onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount); } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) { onSecurityLogsAvailable(context, intent); } else { Log.w(TAG, "Unhandled broadcast: " + action); } } }