blob: 6bcee1413fa835ed463955062aae87316005023c [file] [log] [blame]
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +00001/*
2 * Copyright (C) 2018 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.signedconfig;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.pm.PackageInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.PackageManagerInternal;
26import android.net.Uri;
27import android.os.Bundle;
28import android.util.Slog;
29
30import com.android.server.LocalServices;
31
Mathew Inwood1381c1a2018-12-11 16:19:05 +000032import java.nio.charset.StandardCharsets;
33import java.util.Base64;
34
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +000035/**
36 * Signed config service. This is not an Android Service, but just owns a broadcast receiver for
37 * receiving package install and update notifications from the package manager.
38 */
39public class SignedConfigService {
40
41 private static final boolean DBG = false;
42 private static final String TAG = "SignedConfig";
43
44 // TODO should these be elsewhere? In a public API?
Mathew Inwood44d7ef92019-01-03 15:23:21 +000045 private static final String KEY_GLOBAL_SETTINGS = "android.settings.global";
46 private static final String KEY_GLOBAL_SETTINGS_SIGNATURE = "android.settings.global.signature";
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +000047
48 private static class UpdateReceiver extends BroadcastReceiver {
49 @Override
50 public void onReceive(Context context, Intent intent) {
51 new SignedConfigService(context).handlePackageBroadcast(intent);
52 }
53 }
54
55 private final Context mContext;
56 private final PackageManagerInternal mPacMan;
57
58 public SignedConfigService(Context context) {
59 mContext = context;
60 mPacMan = LocalServices.getService(PackageManagerInternal.class);
61 }
62
63 void handlePackageBroadcast(Intent intent) {
64 if (DBG) Slog.d(TAG, "handlePackageBroadcast " + intent);
65 Uri packageData = intent.getData();
66 String packageName = packageData == null ? null : packageData.getSchemeSpecificPart();
67 if (DBG) Slog.d(TAG, "handlePackageBroadcast package=" + packageName);
68 if (packageName == null) {
69 return;
70 }
71 int userId = mContext.getUser().getIdentifier();
72 PackageInfo pi = mPacMan.getPackageInfo(packageName, PackageManager.GET_META_DATA,
73 android.os.Process.SYSTEM_UID, userId);
74 if (pi == null) {
75 Slog.w(TAG, "Got null PackageInfo for " + packageName + "; user " + userId);
76 return;
77 }
78 Bundle metaData = pi.applicationInfo.metaData;
79 if (metaData == null) {
80 if (DBG) Slog.d(TAG, "handlePackageBroadcast: no metadata");
81 return;
82 }
Mathew Inwood44d7ef92019-01-03 15:23:21 +000083 if (metaData.containsKey(KEY_GLOBAL_SETTINGS)
84 && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) {
85 String config = metaData.getString(KEY_GLOBAL_SETTINGS);
86 String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
Mathew Inwood1381c1a2018-12-11 16:19:05 +000087 try {
88 // Base64 encoding is standard (not URL safe) encoding: RFC4648
89 config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
90 } catch (IllegalArgumentException iae) {
Mathew Inwood44d7ef92019-01-03 15:23:21 +000091 Slog.e(TAG, "Failed to base64 decode global settings config from " + packageName);
Mathew Inwood1381c1a2018-12-11 16:19:05 +000092 return;
93 }
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +000094 if (DBG) {
Mathew Inwood44d7ef92019-01-03 15:23:21 +000095 Slog.d(TAG, "Got global settings config: " + config);
96 Slog.d(TAG, "Got global settings signature: " + signature);
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +000097 }
Mathew Inwood44d7ef92019-01-03 15:23:21 +000098 new GlobalSettingsConfigApplicator(mContext, packageName).applyConfig(
Mathew Inwood1b1639d2018-11-29 16:42:32 +000099 config, signature);
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +0000100 } else {
Mathew Inwood44d7ef92019-01-03 15:23:21 +0000101 if (DBG) Slog.d(TAG, "Package has no global settings config/signature.");
Mathew Inwood4e2ed6a2018-11-26 15:31:16 +0000102 }
103 }
104
105 /**
106 * Register to receive broadcasts from the package manager.
107 */
108 public static void registerUpdateReceiver(Context context) {
109 if (DBG) Slog.d(TAG, "Registering receiver");
110 IntentFilter filter = new IntentFilter();
111 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
112 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
113 filter.addDataScheme("package");
114 context.registerReceiver(new UpdateReceiver(), filter);
115 }
116}