1 /* 2 * Copyright (C) 2020 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.compatibility.common.util; 18 19 import static org.junit.Assert.assertTrue; 20 21 import android.provider.DeviceConfig; 22 import android.util.ArrayMap; 23 24 import androidx.annotation.GuardedBy; 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import java.util.Objects; 29 30 /** 31 * Helper to automatically save multiple existing DeviceConfig values, change them during tests, and 32 * restore the original values after the test. 33 */ 34 public class DeviceConfigStateHelper implements AutoCloseable { 35 private final String mNamespace; 36 @GuardedBy("mOriginalValues") 37 private final ArrayMap<String, String> mOriginalValues = new ArrayMap<>(); 38 39 /** 40 * @param namespace DeviceConfig namespace. 41 */ DeviceConfigStateHelper(@onNull String namespace)42 public DeviceConfigStateHelper(@NonNull String namespace) { 43 mNamespace = Objects.requireNonNull(namespace); 44 } 45 maybeCacheOriginalValueLocked(String key)46 private void maybeCacheOriginalValueLocked(String key) { 47 if (!mOriginalValues.containsKey(key)) { 48 // Only save the current value if we haven't changed it. 49 final String ogValue = SystemUtil.runWithShellPermissionIdentity( 50 () -> DeviceConfig.getProperty(mNamespace, key)); 51 mOriginalValues.put(key, ogValue); 52 } 53 } 54 set(@onNull String key, @Nullable String value)55 public void set(@NonNull String key, @Nullable String value) { 56 synchronized (mOriginalValues) { 57 maybeCacheOriginalValueLocked(key); 58 } 59 SystemUtil.runWithShellPermissionIdentity( 60 () -> assertTrue( 61 DeviceConfig.setProperty(mNamespace, key, value, /* makeDefault */false))); 62 } 63 set(@onNull DeviceConfig.Properties properties)64 public void set(@NonNull DeviceConfig.Properties properties) { 65 synchronized (mOriginalValues) { 66 for (String key : properties.getKeyset()) { 67 maybeCacheOriginalValueLocked(key); 68 } 69 } 70 SystemUtil.runWithShellPermissionIdentity( 71 () -> assertTrue(DeviceConfig.setProperties(properties))); 72 } 73 restoreOriginalValues()74 public void restoreOriginalValues() { 75 final DeviceConfig.Properties.Builder builder = 76 new DeviceConfig.Properties.Builder(mNamespace); 77 synchronized (mOriginalValues) { 78 for (int i = 0; i < mOriginalValues.size(); ++i) { 79 builder.setString(mOriginalValues.keyAt(i), mOriginalValues.valueAt(i)); 80 } 81 mOriginalValues.clear(); 82 } 83 SystemUtil.runWithShellPermissionIdentity( 84 () -> DeviceConfig.setProperties(builder.build())); 85 } 86 87 @Override close()88 public void close() throws Exception { 89 restoreOriginalValues(); 90 } 91 } 92