• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.compatibility.common.util.TestUtils.RunnableWithThrow;
29 
30 import java.util.Objects;
31 
32 /**
33  * Helper to automatically save multiple existing DeviceConfig values, change them during tests, and
34  * restore the original values after the test.
35  */
36 public class DeviceConfigStateHelper implements AutoCloseable {
37     private final String mNamespace;
38     @GuardedBy("mOriginalValues")
39     private final ArrayMap<String, String> mOriginalValues = new ArrayMap<>();
40 
41     /**
42      * @param namespace DeviceConfig namespace.
43      */
DeviceConfigStateHelper(@onNull String namespace)44     public DeviceConfigStateHelper(@NonNull String namespace) {
45         mNamespace = Objects.requireNonNull(namespace);
46     }
47 
maybeCacheOriginalValueLocked(String key)48     private void maybeCacheOriginalValueLocked(String key) {
49         if (!mOriginalValues.containsKey(key)) {
50             // Only save the current value if we haven't changed it.
51             final String ogValue = SystemUtil.runWithShellPermissionIdentity(
52                     () -> DeviceConfig.getProperty(mNamespace, key));
53             mOriginalValues.put(key, ogValue);
54         }
55     }
56 
set(@onNull String key, @Nullable String value)57     public void set(@NonNull String key, @Nullable String value) {
58         synchronized (mOriginalValues) {
59             maybeCacheOriginalValueLocked(key);
60         }
61         SystemUtil.runWithShellPermissionIdentity(
62                 () -> assertTrue(
63                         DeviceConfig.setProperty(mNamespace, key, value, /* makeDefault */false)));
64     }
65 
66     /**
67      * Run a Runnable, with DeviceConfig.setSyncDisabledMode(SYNC_DISABLED_MODE_NONE),
68      * with all the shell permissions.
69      */
callWithSyncEnabledWithShellPermissions(RunnableWithThrow r)70     private void callWithSyncEnabledWithShellPermissions(RunnableWithThrow r) {
71         SystemUtil.runWithShellPermissionIdentity(() -> {
72             final int originalSyncMode = DeviceConfig.getSyncDisabledMode();
73             try {
74                 // TODO: Use DeviceConfig.setSyncDisabledMode, once the SYNC_* constants
75                 // are exposed.
76                 ShellUtils.runShellCommand("cmd device_config set_sync_disabled_for_tests none");
77 
78                 r.run();
79             } finally {
80                 DeviceConfig.setSyncDisabledMode(originalSyncMode);
81             }
82         });
83     }
84 
set(@onNull DeviceConfig.Properties properties)85     public void set(@NonNull DeviceConfig.Properties properties) {
86         synchronized (mOriginalValues) {
87             for (String key : properties.getKeyset()) {
88                 maybeCacheOriginalValueLocked(key);
89             }
90         }
91         callWithSyncEnabledWithShellPermissions(
92                 () -> assertTrue(DeviceConfig.setProperties(properties)));
93     }
94 
restoreOriginalValues()95     public void restoreOriginalValues() {
96         final DeviceConfig.Properties.Builder builder =
97                 new DeviceConfig.Properties.Builder(mNamespace);
98         synchronized (mOriginalValues) {
99             for (int i = 0; i < mOriginalValues.size(); ++i) {
100                 builder.setString(mOriginalValues.keyAt(i), mOriginalValues.valueAt(i));
101             }
102             mOriginalValues.clear();
103         }
104         callWithSyncEnabledWithShellPermissions(
105                 () -> assertTrue(DeviceConfig.setProperties(builder.build())));
106     }
107 
108     @Override
close()109     public void close() throws Exception {
110         restoreOriginalValues();
111     }
112 }
113