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 17package com.android.server.am; 18 19import android.content.ContentResolver; 20import android.database.ContentObserver; 21import android.net.Uri; 22import android.os.Build; 23import android.os.SystemProperties; 24import android.provider.Settings; 25import android.text.TextUtils; 26import android.util.Slog; 27import android.view.ThreadedRenderer; 28 29import com.android.internal.annotations.VisibleForTesting; 30import com.android.internal.util.Preconditions; 31 32/** 33 * Maps global system settings to system properties. 34 * <p>The properties are dynamically updated when settings change. 35 */ 36class GlobalSettingsToPropertiesMapper { 37 38 private static final String TAG = "GlobalSettingsToPropertiesMapper"; 39 40 // List mapping entries in the following format: 41 // {Settings.Global.SETTING_NAME, "system_property_name"} 42 // Important: Property being added should be whitelisted by SELinux policy or have one of the 43 // already whitelisted prefixes in system_server.te, e.g. sys. 44 private static final String[][] sGlobalSettingsMapping = new String[][] { 45 {Settings.Global.SYS_VDSO, "sys.vdso"}, 46 {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR}, 47 {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"}, 48 {Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"}, 49 {Settings.Global.SYS_TRACED, "sys.traced.enable_override"}, 50 }; 51 52 53 private final ContentResolver mContentResolver; 54 private final String[][] mGlobalSettingsMapping; 55 56 @VisibleForTesting 57 GlobalSettingsToPropertiesMapper(ContentResolver contentResolver, 58 String[][] globalSettingsMapping) { 59 mContentResolver = contentResolver; 60 mGlobalSettingsMapping = globalSettingsMapping; 61 } 62 63 void updatePropertiesFromGlobalSettings() { 64 for (String[] entry : mGlobalSettingsMapping) { 65 final String settingName = entry[0]; 66 final String propName = entry[1]; 67 Uri settingUri = Settings.Global.getUriFor(settingName); 68 Preconditions.checkNotNull(settingUri, "Setting " + settingName + " not found"); 69 ContentObserver co = new ContentObserver(null) { 70 @Override 71 public void onChange(boolean selfChange) { 72 updatePropertyFromSetting(settingName, propName); 73 } 74 }; 75 updatePropertyFromSetting(settingName, propName); 76 mContentResolver.registerContentObserver(settingUri, false, co); 77 } 78 } 79 80 public static void start(ContentResolver contentResolver) { 81 new GlobalSettingsToPropertiesMapper(contentResolver, sGlobalSettingsMapping) 82 .updatePropertiesFromGlobalSettings(); 83 } 84 85 private String getGlobalSetting(String name) { 86 return Settings.Global.getString(mContentResolver, name); 87 } 88 89 private void setProperty(String key, String value) { 90 // Check if need to clear the property 91 if (value == null) { 92 // It's impossible to remove system property, therefore we check previous value to 93 // avoid setting an empty string if the property wasn't set. 94 if (TextUtils.isEmpty(systemPropertiesGet(key))) { 95 return; 96 } 97 value = ""; 98 } 99 try { 100 systemPropertiesSet(key, value); 101 } catch (Exception e) { 102 // Failure to set a property can be caused by SELinux denial. This usually indicates 103 // that the property wasn't whitelisted in sepolicy. 104 // No need to report it on all user devices, only on debug builds. 105 if (Build.IS_DEBUGGABLE) { 106 Slog.wtf(TAG, "Unable to set property " + key + " value '" + value + "'", e); 107 } else { 108 Slog.e(TAG, "Unable to set property " + key + " value '" + value + "'", e); 109 } 110 } 111 } 112 113 @VisibleForTesting 114 protected String systemPropertiesGet(String key) { 115 return SystemProperties.get(key); 116 } 117 118 @VisibleForTesting 119 protected void systemPropertiesSet(String key, String value) { 120 SystemProperties.set(key, value); 121 } 122 123 @VisibleForTesting 124 void updatePropertyFromSetting(String settingName, String propName) { 125 String settingValue = getGlobalSetting(settingName); 126 setProperty(propName, settingValue); 127 } 128} 129