1 /* 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 17 package com.android.server.signedconfig; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.pm.PackageInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.PackageManagerInternal; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.util.Slog; 29 import android.util.StatsLog; 30 31 import com.android.server.LocalServices; 32 33 import java.nio.charset.StandardCharsets; 34 import java.util.Base64; 35 36 /** 37 * Signed config service. This is not an Android Service, but just owns a broadcast receiver for 38 * receiving package install and update notifications from the package manager. 39 */ 40 public class SignedConfigService { 41 42 private static final boolean DBG = false; 43 private static final String TAG = "SignedConfig"; 44 45 // TODO should these be elsewhere? In a public API? 46 private static final String KEY_GLOBAL_SETTINGS = "android.settings.global"; 47 private static final String KEY_GLOBAL_SETTINGS_SIGNATURE = "android.settings.global.signature"; 48 49 private static class UpdateReceiver extends BroadcastReceiver { 50 @Override onReceive(Context context, Intent intent)51 public void onReceive(Context context, Intent intent) { 52 new SignedConfigService(context).handlePackageBroadcast(intent); 53 } 54 } 55 56 private final Context mContext; 57 private final PackageManagerInternal mPacMan; 58 SignedConfigService(Context context)59 public SignedConfigService(Context context) { 60 mContext = context; 61 mPacMan = LocalServices.getService(PackageManagerInternal.class); 62 } 63 handlePackageBroadcast(Intent intent)64 void handlePackageBroadcast(Intent intent) { 65 if (DBG) Slog.d(TAG, "handlePackageBroadcast " + intent); 66 Uri packageData = intent.getData(); 67 String packageName = packageData == null ? null : packageData.getSchemeSpecificPart(); 68 if (DBG) Slog.d(TAG, "handlePackageBroadcast package=" + packageName); 69 if (packageName == null) { 70 return; 71 } 72 int userId = mContext.getUser().getIdentifier(); 73 PackageInfo pi = mPacMan.getPackageInfo(packageName, PackageManager.GET_META_DATA, 74 android.os.Process.SYSTEM_UID, userId); 75 if (pi == null) { 76 Slog.w(TAG, "Got null PackageInfo for " + packageName + "; user " + userId); 77 return; 78 } 79 Bundle metaData = pi.applicationInfo.metaData; 80 if (metaData == null) { 81 if (DBG) Slog.d(TAG, "handlePackageBroadcast: no metadata"); 82 return; 83 } 84 if (metaData.containsKey(KEY_GLOBAL_SETTINGS) 85 && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) { 86 SignedConfigEvent event = new SignedConfigEvent(); 87 try { 88 event.type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS; 89 event.fromPackage = packageName; 90 String config = metaData.getString(KEY_GLOBAL_SETTINGS); 91 String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE); 92 try { 93 // Base64 encoding is standard (not URL safe) encoding: RFC4648 94 config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8); 95 } catch (IllegalArgumentException iae) { 96 Slog.e(TAG, "Failed to base64 decode global settings config from " 97 + packageName); 98 event.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG; 99 return; 100 } 101 if (DBG) { 102 Slog.d(TAG, "Got global settings config: " + config); 103 Slog.d(TAG, "Got global settings signature: " + signature); 104 } 105 new GlobalSettingsConfigApplicator(mContext, packageName, event).applyConfig( 106 config, signature); 107 } finally { 108 event.send(); 109 } 110 } else { 111 if (DBG) Slog.d(TAG, "Package has no global settings config/signature."); 112 } 113 } 114 115 /** 116 * Register to receive broadcasts from the package manager. 117 */ registerUpdateReceiver(Context context)118 public static void registerUpdateReceiver(Context context) { 119 if (DBG) Slog.d(TAG, "Registering receiver"); 120 IntentFilter filter = new IntentFilter(); 121 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 122 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 123 filter.addDataScheme("package"); 124 context.registerReceiver(new UpdateReceiver(), filter); 125 } 126 } 127