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.providers.settings; 18 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertNotNull; 21 import static junit.framework.Assert.assertNull; 22 23 import android.content.ContentResolver; 24 import android.os.Bundle; 25 import android.provider.Settings; 26 27 import androidx.test.InstrumentationRegistry; 28 import androidx.test.runner.AndroidJUnit4; 29 30 import libcore.io.Streams; 31 32 import org.junit.After; 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.io.FileInputStream; 38 import java.io.IOException; 39 import java.io.InputStream; 40 41 /** 42 * Tests for {@link DeviceConfigService}. 43 */ 44 @RunWith(AndroidJUnit4.class) 45 public class DeviceConfigServiceTest { 46 private static final String sNamespace = "namespace1"; 47 private static final String sKey = "key1"; 48 private static final String sValue = "value1"; 49 50 private ContentResolver mContentResolver; 51 52 @Before setUp()53 public void setUp() { 54 mContentResolver = InstrumentationRegistry.getContext().getContentResolver(); 55 } 56 57 @After cleanUp()58 public void cleanUp() { 59 deleteFromContentProvider(mContentResolver, sNamespace, sKey); 60 } 61 62 @Test testPut()63 public void testPut() throws Exception { 64 final String newNamespace = "namespace2"; 65 final String newValue = "value2"; 66 67 String result = getFromContentProvider(mContentResolver, sNamespace, sKey); 68 assertNull(result); 69 70 try { 71 executeShellCommand("device_config put " + sNamespace + " " + sKey + " " + sValue); 72 executeShellCommand("device_config put " + newNamespace + " " + sKey + " " + newValue); 73 74 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 75 assertEquals(sValue, result); 76 result = getFromContentProvider(mContentResolver, newNamespace, sKey); 77 assertEquals(newValue, result); 78 } finally { 79 deleteFromContentProvider(mContentResolver, newNamespace, sKey); 80 } 81 } 82 83 @Test testPut_invalidArgs()84 public void testPut_invalidArgs() throws Exception { 85 // missing sNamespace 86 executeShellCommand("device_config put " + sKey + " " + sValue); 87 String result = getFromContentProvider(mContentResolver, sNamespace, sKey); 88 // still null 89 assertNull(result); 90 91 // too many arguments 92 executeShellCommand( 93 "device_config put " + sNamespace + " " + sKey + " " + sValue + " extra_arg"); 94 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 95 // still null 96 assertNull(result); 97 } 98 99 @Test testDelete()100 public void testDelete() throws Exception { 101 final String newNamespace = "namespace2"; 102 103 putWithContentProvider(mContentResolver, sNamespace, sKey, sValue); 104 putWithContentProvider(mContentResolver, newNamespace, sKey, sValue); 105 String result = getFromContentProvider(mContentResolver, sNamespace, sKey); 106 assertEquals(sValue, result); 107 result = getFromContentProvider(mContentResolver, newNamespace, sKey); 108 assertEquals(sValue, result); 109 110 try { 111 executeShellCommand("device_config delete " + sNamespace + " " + sKey); 112 // sKey is deleted from sNamespace 113 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 114 assertNull(result); 115 // sKey is not deleted from newNamespace 116 result = getFromContentProvider(mContentResolver, newNamespace, sKey); 117 assertEquals(sValue, result); 118 } finally { 119 deleteFromContentProvider(mContentResolver, newNamespace, sKey); 120 } 121 } 122 123 @Test testDelete_invalidArgs()124 public void testDelete_invalidArgs() throws Exception { 125 putWithContentProvider(mContentResolver, sNamespace, sKey, sValue); 126 String result = getFromContentProvider(mContentResolver, sNamespace, sKey); 127 assertEquals(sValue, result); 128 129 // missing sNamespace 130 executeShellCommand("device_config delete " + sKey); 131 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 132 // sValue was not deleted 133 assertEquals(sValue, result); 134 135 // too many arguments 136 executeShellCommand("device_config delete " + sNamespace + " " + sKey + " extra_arg"); 137 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 138 // sValue was not deleted 139 assertEquals(sValue, result); 140 } 141 142 @Test testReset()143 public void testReset() throws Exception { 144 String newValue = "value2"; 145 146 // make sValue the default value 147 executeShellCommand( 148 "device_config put " + sNamespace + " " + sKey + " " + sValue + " default"); 149 // make newValue the current value (as set by a untrusted package) 150 executeShellCommand( 151 "device_config put " + sNamespace + " " + sKey + " " + newValue); 152 String result = getFromContentProvider(mContentResolver, sNamespace, sKey); 153 assertEquals(newValue, result); 154 155 // reset values that were set by untrusted packages 156 executeShellCommand("device_config reset untrusted_defaults " + sNamespace); 157 result = getFromContentProvider(mContentResolver, sNamespace, sKey); 158 // the current value was set by a untrusted package, so it's reset 159 assertEquals(sValue, result); 160 } 161 executeShellCommand(String command)162 private static void executeShellCommand(String command) throws IOException { 163 InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation() 164 .getUiAutomation().executeShellCommand(command).getFileDescriptor()); 165 Streams.readFully(is); 166 } 167 putWithContentProvider(ContentResolver resolver, String namespace, String key, String value)168 private static void putWithContentProvider(ContentResolver resolver, String namespace, 169 String key, String value) { 170 putWithContentProvider(resolver, namespace, key, value, false); 171 } 172 putWithContentProvider(ContentResolver resolver, String namespace, String key, String value, boolean makeDefault)173 private static void putWithContentProvider(ContentResolver resolver, String namespace, 174 String key, String value, boolean makeDefault) { 175 String compositeName = namespace + "/" + key; 176 Bundle args = new Bundle(); 177 args.putString(Settings.NameValueTable.VALUE, value); 178 if (makeDefault) { 179 args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true); 180 } 181 resolver.call( 182 Settings.Config.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, compositeName, args); 183 } 184 getFromContentProvider(ContentResolver resolver, String namespace, String key)185 private static String getFromContentProvider(ContentResolver resolver, String namespace, 186 String key) { 187 String compositeName = namespace + "/" + key; 188 Bundle result = resolver.call( 189 Settings.Config.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, compositeName, null); 190 assertNotNull(result); 191 return result.getString(Settings.NameValueTable.VALUE); 192 } 193 deleteFromContentProvider(ContentResolver resolver, String namespace, String key)194 private static boolean deleteFromContentProvider(ContentResolver resolver, String namespace, 195 String key) { 196 String compositeName = namespace + "/" + key; 197 Bundle result = resolver.call( 198 Settings.Config.CONTENT_URI, 199 Settings.CALL_METHOD_DELETE_CONFIG, compositeName, null); 200 assertNotNull(result); 201 return compositeName.equals(result.getString(Settings.NameValueTable.VALUE)); 202 } 203 } 204