blob: 1933fe750e751ba2b819e7fd2cfffe7245848359 [file] [log] [blame]
/*
* Copyright (C) 2017 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 com.android.server.devicepolicy;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.security.KeyChain.KeyChainConnection;
import android.util.Log;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
protected static final int MONITORING_CERT_NOTIFICATION_ID = R.plurals.ssl_ca_cert_warning;
private final DevicePolicyManagerService mService;
private final DevicePolicyManagerService.Injector mInjector;
public MonitoringCertNotificationTask(final DevicePolicyManagerService service,
final DevicePolicyManagerService.Injector injector) {
super();
mService = service;
mInjector = injector;
}
@Override
protected Void doInBackground(Integer... params) {
int userHandle = params[0];
if (userHandle == UserHandle.USER_ALL) {
for (UserInfo userInfo : mInjector.getUserManager().getUsers(true)) {
repostOrClearNotification(userInfo.getUserHandle());
}
} else {
repostOrClearNotification(UserHandle.of(userHandle));
}
return null;
}
private void repostOrClearNotification(UserHandle userHandle) {
if (!mInjector.getUserManager().isUserUnlocked(userHandle.getIdentifier())) {
return;
}
// Call out to KeyChain to check for CAs which are waiting for approval.
final int pendingCertificateCount;
try {
pendingCertificateCount = mService.retainAcceptedCertificates(
userHandle, getInstalledCaCertificates(userHandle));
} catch (RemoteException | RuntimeException e) {
Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
return;
}
if (pendingCertificateCount != 0) {
showNotification(userHandle, pendingCertificateCount);
} else {
mInjector.getNotificationManager().cancelAsUser(
LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, userHandle);
}
}
private void showNotification(UserHandle userHandle, int pendingCertificateCount) {
// Create a context for the target user.
final Context userContext;
try {
userContext = mInjector.createContextAsUser(userHandle);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
return;
}
// Build and show a warning notification
int smallIconId;
String contentText;
int parentUserId = userHandle.getIdentifier();
Resources resources = mInjector.getResources();
if (mService.getProfileOwner(userHandle.getIdentifier()) != null) {
contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
mService.getProfileOwnerName(userHandle.getIdentifier()));
smallIconId = R.drawable.stat_sys_certificate_info;
parentUserId = mService.getProfileParentId(userHandle.getIdentifier());
} else if (mService.getDeviceOwnerUserId() == userHandle.getIdentifier()) {
contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
mService.getDeviceOwnerName());
smallIconId = R.drawable.stat_sys_certificate_info;
} else {
contentText = resources.getString(R.string.ssl_ca_cert_noti_by_unknown);
smallIconId = android.R.drawable.stat_sys_warning;
}
Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// TODO this next line is taken from original notification code in
// {@link DevicePolicyManagerService} but not a very good way of doing it. Do it better.
dialogIntent.setPackage("com.android.settings");
dialogIntent.putExtra(Settings.EXTRA_NUMBER_OF_CERTIFICATES, pendingCertificateCount);
dialogIntent.putExtra(Intent.EXTRA_USER_ID, userHandle.getIdentifier());
PendingIntent notifyIntent = PendingIntent.getActivityAsUser(userContext, 0,
dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
UserHandle.of(parentUserId));
final Notification noti =
new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
.setSmallIcon(smallIconId)
.setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
pendingCertificateCount))
.setContentText(contentText)
.setContentIntent(notifyIntent)
.setShowWhen(false)
.setColor(R.color.system_notification_accent_color)
.build();
mInjector.getNotificationManager().notifyAsUser(
LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
}
private List<String> getInstalledCaCertificates(UserHandle userHandle)
throws RemoteException, RuntimeException {
try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
return conn.getService().getUserCaAliases().getList();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} catch (AssertionError e) {
throw new RuntimeException(e);
}
}
}