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