blob: 2f681a3f568e296a6fa2d8025ed6cd71ce96c166 [file] [log] [blame]
Robin Leebd107772017-03-23 15:28:37 +00001/*
2 * Copyright (C) 2017 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
17package com.android.server.security;
18
19import android.content.BroadcastReceiver;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.os.Process;
26import android.os.UserHandle;
27import android.security.IKeyChainService;
28import android.util.Slog;
29
30import com.android.server.DeviceIdleController;
31import com.android.server.LocalServices;
32import com.android.server.SystemService;
33
34/**
35 * Service related to {@link android.security.KeyChain}.
36 * <p>
37 * Most of the implementation of KeyChain is provided by the com.android.keychain app. Until O,
38 * this was OK because a system app has roughly the same privileges as the system process.
39 * <p>
40 * With the introduction of background check, PACKAGE_* broadcasts (_ADDED, _REMOVED, _REPLACED)
41 * aren't received when the KeyChain app is in the background, which is bad as it uses those to
42 * drive internal cleanup.
43 * <p>
44 * TODO (b/35968281): take a more sophisticated look at what bits of KeyChain should be inside the
45 * system server and which make sense inside a system app.
46 */
47public class KeyChainSystemService extends SystemService {
48
49 private static final String TAG = "KeyChainSystemService";
50
51 /**
52 * Maximum time limit for the KeyChain app to deal with packages being removed.
53 */
54 private static final int KEYCHAIN_IDLE_WHITELIST_DURATION_MS = 30 * 1000;
55
56 public KeyChainSystemService(final Context context) {
57 super(context);
58 }
59
60 @Override
61 public void onStart() {
62 IntentFilter packageFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
63 packageFilter.addDataScheme("package");
64 try {
65 getContext().registerReceiverAsUser(mPackageReceiver, UserHandle.ALL,
66 packageFilter, null /*broadcastPermission*/, null /*handler*/);
67 } catch (RuntimeException e) {
68 Slog.w(TAG, "Unable to register for package removed broadcast", e);
69 }
70 }
71
72 private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
73 @Override
74 public void onReceive(final Context context, final Intent broadcastIntent) {
75 if (broadcastIntent.getPackage() != null) {
76 return;
77 }
78
79 try {
80 final Intent intent = new Intent(IKeyChainService.class.getName());
81 ComponentName service =
82 intent.resolveSystemService(getContext().getPackageManager(), 0 /*flags*/);
83 if (service == null) {
84 return;
85 }
86 intent.setComponent(service);
87 intent.setAction(broadcastIntent.getAction());
88 startServiceInBackgroundAsUser(intent, UserHandle.of(getSendingUserId()));
89 } catch (RuntimeException e) {
90 Slog.e(TAG, "Unable to forward package removed broadcast to KeyChain", e);
91 }
92 }
93 };
94
95
96 private void startServiceInBackgroundAsUser(final Intent intent, final UserHandle user) {
97 if (intent.getComponent() == null) {
98 return;
99 }
100
101 final String packageName = intent.getComponent().getPackageName();
102 final DeviceIdleController.LocalService idleController =
103 LocalServices.getService(DeviceIdleController.LocalService.class);
104 idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
105 KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
106
107 getContext().startServiceAsUser(intent, user);
108 }
109}