1 /*
2  * Copyright (C) 2015 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 package com.android.compatibility.common.tradefed.targetprep;
17 
18 import static com.android.tradefed.targetprep.UserHelper.RUN_TESTS_AS_USER_KEY;
19 
20 import com.android.tradefed.config.Option;
21 import com.android.tradefed.config.OptionClass;
22 import com.android.tradefed.device.DeviceNotAvailableException;
23 import com.android.tradefed.device.ITestDevice;
24 import com.android.tradefed.invoker.TestInformation;
25 import com.android.tradefed.log.LogUtil.CLog;
26 import com.android.tradefed.result.error.DeviceErrorIdentifier;
27 import com.android.tradefed.targetprep.BuildError;
28 import com.android.tradefed.targetprep.TargetSetupError;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Checks that a given setting on the device is one of the given values
35  */
36 @OptionClass(alias="settings-preparer")
37 public class SettingsPreparer extends PreconditionPreparer {
38 
39     public enum SettingType {
40         SECURE,
41         GLOBAL,
42         SYSTEM;
43     }
44 
45     /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
46      * the SettingsPreparer class can define mSettingName at runtime */
47     @Option(name = "device-setting", description = "The setting on the device to be checked")
48     protected String mSettingName = null;
49 
50     /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
51      * the SettingsPreparer class can define mSettingType at runtime */
52     @Option(name = "setting-type",
53             description = "If the setting is 'secure', 'global', or 'system'")
54     protected SettingType mSettingType = null;
55 
56     @Option(name = "set-value", description = "The value to be set for the setting")
57     protected String mSetValue = null;
58 
59     @Option(name = "expected-values", description = "The set of expected values of the setting")
60     protected List<String> mExpectedSettingValues = new ArrayList<String>();
61 
62     @Option(name = "failure-message", description = "The text printed for an unexpected value")
63     protected String mFailureMessage = null;
64 
65     @Override
run(TestInformation testInfo)66     public void run(TestInformation testInfo)
67             throws TargetSetupError, BuildError, DeviceNotAvailableException {
68         ITestDevice device = testInfo.getDevice();
69         if (mSettingName == null) {
70             throw new TargetSetupError("The \"device-setting\" option must be defined for the " +
71                     "SettingsPreparer class", device.getDeviceDescriptor());
72         }
73 
74         if (mSettingType == null) {
75             throw new TargetSetupError("The \"setting-type\" option must be defined for the " +
76                     "SettingsPreparer class", device.getDeviceDescriptor());
77         }
78 
79         /* At least one of the options "set-value" and "expected-values" must be set */
80         if (mSetValue == null && mExpectedSettingValues.isEmpty()) {
81             throw new TargetSetupError("At least one of the options \"set-value\" and " +
82                     "\"expected-values\" must be set", device.getDeviceDescriptor());
83         }
84 
85         String testUser = testInfo.properties().get(RUN_TESTS_AS_USER_KEY);
86         String userArg = " ";
87         if (testUser != null && !testUser.isEmpty() && mSettingType != SettingType.GLOBAL) {
88             userArg = String.format(" --user %s ", testUser);
89         }
90 
91         String shellCmdGet =
92                 !mExpectedSettingValues.isEmpty()
93                         ? String.format("settings get %s%s%s", mSettingType, userArg, mSettingName)
94                         : "";
95         String shellCmdPut =
96                 (mSetValue != null)
97                         ? String.format(
98                                 "settings put %s%s%s %s",
99                                 mSettingType, userArg, mSettingName, mSetValue)
100                         : "";
101 
102         /* Case 1: Both expected-values and set-value are given */
103         if (mSetValue != null && !mExpectedSettingValues.isEmpty()) {
104             // first ensure that the set-value given can be found in expected-values
105             if (!mExpectedSettingValues.contains(mSetValue)) {
106                 throw new TargetSetupError(
107                         String.format(
108                                 "set-value for %s is %s, but value not found in expected-values:"
109                                         + " %s",
110                                 mSettingName, mSetValue, mExpectedSettingValues.toString()),
111                         device.getDeviceDescriptor(),
112                         DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE);
113             }
114             String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
115             // only change unexpected setting value
116             if (!mExpectedSettingValues.contains(currentSettingValue)) {
117                 CLog.d("Changing value for %s from %s to %s",
118                         mSettingName, currentSettingValue, mSetValue);
119                 device.executeShellCommand(shellCmdPut);
120             }
121             return;
122         }
123 
124         /* Case 2: Only set-value given */
125         if (mSetValue != null) {
126             CLog.d("Setting %s to value %s", mSettingName, mSetValue);
127             device.executeShellCommand(shellCmdPut);
128             return;
129         }
130 
131         /* Case 3: Only expected-values given */
132         String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
133         if (!mExpectedSettingValues.contains(currentSettingValue)) {
134             if (mFailureMessage == null) {
135                 mFailureMessage = String.format(
136                         "Device setting \"%s\" returned \"%s\", not found in %s",
137                         mSettingName, currentSettingValue, mExpectedSettingValues.toString());
138             }
139             throw new TargetSetupError(
140                     mFailureMessage,
141                     device.getDeviceDescriptor(),
142                     DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE);
143         }
144     }
145 
146 }
147