1 /*
2  * Copyright (C) 2012 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.tradefed.targetprep;
17 
18 import com.android.tradefed.config.Option;
19 import com.android.tradefed.config.OptionClass;
20 import com.android.tradefed.dependencies.ExternalDependency;
21 import com.android.tradefed.dependencies.IExternalDependency;
22 import com.android.tradefed.dependencies.connectivity.NetworkDependency;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.device.ITestDevice;
25 import com.android.tradefed.device.LocalAndroidVirtualDevice;
26 import com.android.tradefed.device.cloud.NestedRemoteDevice;
27 import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
28 import com.android.tradefed.invoker.TestInformation;
29 import com.android.tradefed.invoker.logger.InvocationMetricLogger;
30 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey;
31 import com.android.tradefed.log.LogUtil.CLog;
32 import com.android.tradefed.result.error.InfraErrorIdentifier;
33 
34 import com.google.common.base.Strings;
35 
36 import java.util.LinkedHashSet;
37 import java.util.Set;
38 
39 /**
40  * A {@link ITargetPreparer} that configures wifi on the device if necessary.
41  *
42  * <p>Unlike {@link DeviceSetup}, this preparer works when adb is not root aka user builds.
43  */
44 @OptionClass(alias = "wifi")
45 public class WifiPreparer extends BaseTargetPreparer implements IExternalDependency {
46 
47     @Option(name="wifi-network", description="the name of wifi network to connect to.")
48     private String mWifiNetwork = null;
49 
50     @Option(name="wifi-psk", description="WPA-PSK passphrase of wifi network to connect to.")
51     private String mWifiPsk = null;
52 
53     @Option(name = "disconnect-wifi-after-test", description =
54             "disconnect from wifi network after test completes.")
55     private boolean mDisconnectWifiAfterTest = true;
56 
57     @Option(name = "monitor-network", description =
58             "monitor network connectivity during test.")
59     private boolean mMonitorNetwork = true;
60 
61     @Option(name = "skip", description = "skip the connectivity check and wifi setup")
62     private boolean mSkip = false;
63 
64     @Option(name = "verify-only", description = "Skip setup and verify a wifi connection.")
65     private boolean mVerifyOnly = false;
66 
67     /** {@inheritDoc} */
68     @Override
setUp(TestInformation testInfo)69     public void setUp(TestInformation testInfo)
70             throws TargetSetupError, BuildError, DeviceNotAvailableException {
71         if (mSkip) {
72             return;
73         }
74         ITestDevice device = testInfo.getDevice();
75         if (mVerifyOnly) {
76             if (!device.isWifiEnabled()) {
77                 throw new TargetSetupError(
78                         "The device does not have wifi enabled.",
79                         device.getDeviceDescriptor(),
80                         InfraErrorIdentifier.NO_WIFI);
81             } else if (!device.checkConnectivity()) {
82                 throw new TargetSetupError(
83                         "The device has no wifi connection.",
84                         device.getDeviceDescriptor(),
85                         InfraErrorIdentifier.NO_WIFI);
86             }
87             return;
88         }
89 
90         if (mWifiNetwork == null) {
91             throw new TargetSetupError(
92                     "wifi-network not specified",
93                     device.getDeviceDescriptor(),
94                     InfraErrorIdentifier.OPTION_CONFIGURATION_ERROR);
95         }
96 
97         InvocationMetricLogger.addInvocationMetrics(InvocationMetricKey.WIFI_AP_NAME, mWifiNetwork);
98         if (!device.connectToWifiNetworkIfNeeded(mWifiNetwork, mWifiPsk)) {
99             InfraErrorIdentifier errorIdentifier = InfraErrorIdentifier.WIFI_FAILED_CONNECT;
100             if (device instanceof RemoteAndroidVirtualDevice
101                     || device instanceof NestedRemoteDevice
102                     || device instanceof LocalAndroidVirtualDevice) {
103                 // Error identifier for virtual devices.
104                 errorIdentifier = InfraErrorIdentifier.VIRTUAL_WIFI_FAILED_CONNECT;
105             }
106             throw new TargetSetupError(
107                     String.format(
108                             "Failed to connect to wifi network %s on %s",
109                             mWifiNetwork, device.getSerialNumber()),
110                     device.getDeviceDescriptor(),
111                     errorIdentifier);
112         }
113         if (mMonitorNetwork) {
114             device.enableNetworkMonitor();
115         }
116     }
117 
118     /** {@inheritDoc} */
119     @Override
tearDown(TestInformation testInfo, Throwable e)120     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
121         if (mSkip || mVerifyOnly) {
122             return;
123         }
124         ITestDevice device = testInfo.getDevice();
125         if (e instanceof DeviceFailedToBootError) {
126             CLog.d("boot failure: skipping wifi teardown");
127             return;
128         }
129         if (e instanceof DeviceNotAvailableException) {
130             CLog.d("device is not available. skipping wifi teardown");
131             return;
132         }
133 
134         if (mMonitorNetwork) {
135             device.disableNetworkMonitor();
136         }
137 
138         if (mWifiNetwork != null && mDisconnectWifiAfterTest && device.isWifiEnabled()) {
139             if (!device.disconnectFromWifi()) {
140                 CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber());
141                 return;
142             }
143             CLog.i("Successfully disconnected from wifi network on %s", device.getSerialNumber());
144         }
145     }
146 
147     @Override
getDependencies()148     public Set<ExternalDependency> getDependencies() {
149         Set<ExternalDependency> externalDependencies = new LinkedHashSet<>();
150         if (!mSkip && (mVerifyOnly || !Strings.isNullOrEmpty(mWifiNetwork))) {
151             externalDependencies.add(new NetworkDependency());
152         }
153         return externalDependencies;
154     }
155 }
156