blob: 4771e2bc1a45fe012a2e7087e69eece294b59450 [file] [log] [blame]
Julien Desprez6961b272016-02-01 09:58:23 +00001/*
2 * Copyright (C) 2016 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 */
16package com.android.tradefed.device;
17
Julien Desprez0b2263a2019-02-20 10:02:56 -080018import com.android.annotations.VisibleForTesting;
Julien Desprez227af682016-06-01 15:02:58 +010019import com.android.ddmlib.AdbCommandRejectedException;
Julien Desprez6961b272016-02-01 09:58:23 +000020import com.android.ddmlib.IDevice;
Julien Desprez895e4b12016-08-01 09:44:37 +010021import com.android.ddmlib.IDevice.DeviceState;
Julien Desprez227af682016-06-01 15:02:58 +010022import com.android.ddmlib.ShellCommandUnresponsiveException;
23import com.android.ddmlib.TimeoutException;
Julien Desprez6961b272016-02-01 09:58:23 +000024import com.android.tradefed.device.DeviceManager.FastbootDevice;
Julien Desprez13cf90c2018-12-21 14:47:44 -080025import com.android.tradefed.device.cloud.ManagedRemoteDevice;
Julien Desprez088e5c92019-03-20 09:10:25 -070026import com.android.tradefed.device.cloud.NestedDeviceStateMonitor;
Julien Desprez0b2263a2019-02-20 10:02:56 -080027import com.android.tradefed.device.cloud.NestedRemoteDevice;
Julien Desprez140f2b12018-11-30 13:31:06 -080028import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
Julien Desprez13cf90c2018-12-21 14:47:44 -080029import com.android.tradefed.device.cloud.VmRemoteDevice;
Julien Desprez227af682016-06-01 15:02:58 +010030import com.android.tradefed.log.LogUtil.CLog;
Julien Desprez493e2642016-08-17 17:49:53 +010031import com.android.tradefed.util.IRunUtil;
32import com.android.tradefed.util.RunUtil;
Julien Desprez83977b92019-07-19 09:37:07 -070033import com.android.tradefed.util.SystemUtil;
Julien Desprez227af682016-06-01 15:02:58 +010034
35import java.io.IOException;
36import java.util.concurrent.TimeUnit;
Julien Desprez59e0e3a2016-06-13 11:07:22 +010037import java.util.regex.Matcher;
38import java.util.regex.Pattern;
39
Julien Desprez6961b272016-02-01 09:58:23 +000040/**
41 * Factory to create the different kind of devices that can be monitored by Tf
42 */
43public class ManagedTestDeviceFactory implements IManagedTestDeviceFactory {
44
Julien Desprezd1bddbd2018-11-15 15:58:38 -080045 public static final String IPADDRESS_PATTERN =
46 "((^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
47 + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
48 + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
49 + "([01]?\\d\\d?|2[0-4]\\d|25[0-5]))|(localhost)){1}";
Julien Desprez59e0e3a2016-06-13 11:07:22 +010050
Julien Desprezc8474552016-02-17 10:59:27 +000051 protected boolean mFastbootEnabled;
52 protected IDeviceManager mDeviceManager;
53 protected IDeviceMonitor mAllocationMonitor;
Julien Desprez6f8743f2016-07-29 10:02:01 +010054 protected static final String CHECK_PM_CMD = "ls %s";
55 protected static final String EXPECTED_RES = "/system/bin/pm";
Julien Desprez493e2642016-08-17 17:49:53 +010056 protected static final String EXPECTED_ERROR = "No such file or directory";
57 protected static final long FRAMEWORK_CHECK_SLEEP_MS = 500;
58 protected static final int FRAMEWORK_CHECK_MAX_RETRY = 3;
Julien Desprez6961b272016-02-01 09:58:23 +000059
60 public ManagedTestDeviceFactory(boolean fastbootEnabled, IDeviceManager deviceManager,
61 IDeviceMonitor allocationMonitor) {
62 mFastbootEnabled = fastbootEnabled;
63 mDeviceManager = deviceManager;
64 mAllocationMonitor = allocationMonitor;
65 }
66
67 /**
68 * {@inheritDoc}
69 */
70 @Override
71 public IManagedTestDevice createDevice(IDevice idevice) {
Julien Desprez227af682016-06-01 15:02:58 +010072 IManagedTestDevice testDevice = null;
Julien Desprez13cf90c2018-12-21 14:47:44 -080073 if (idevice instanceof VmRemoteDevice) {
74 testDevice =
75 new ManagedRemoteDevice(
76 idevice,
77 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
78 mAllocationMonitor);
79 testDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE);
80 } else if (idevice instanceof RemoteAvdIDevice) {
Julien Desprez140f2b12018-11-30 13:31:06 -080081 testDevice =
82 new RemoteAndroidVirtualDevice(
83 idevice,
84 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
85 mAllocationMonitor);
Julien Desprez140f2b12018-11-30 13:31:06 -080086 testDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE);
Hsin-Yi Chen746b86d2019-11-14 05:38:00 +000087 } else if (idevice instanceof StubLocalAndroidVirtualDevice) {
88 // Virtual device to be launched by TradeFed locally.
89 testDevice =
90 new LocalAndroidVirtualDevice(
91 idevice,
92 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
93 mAllocationMonitor);
Julien Desprez0b2263a2019-02-20 10:02:56 -080094 } else if (idevice instanceof TcpDevice) {
Julien Desprez26bee8d2016-03-29 12:09:48 +010095 // Special device for Tcp device for custom handling.
96 testDevice = new RemoteAndroidDevice(idevice,
97 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
98 mAllocationMonitor);
99 testDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE);
Julien Desprez0b2263a2019-02-20 10:02:56 -0800100 } else if (isTcpDeviceSerial(idevice.getSerialNumber())) {
101 if (isRemoteEnvironment()) {
102 // If we are in a remote environment, treat the device as such
103 testDevice =
104 new NestedRemoteDevice(
105 idevice,
Julien Desprez088e5c92019-03-20 09:10:25 -0700106 new NestedDeviceStateMonitor(
107 mDeviceManager, idevice, mFastbootEnabled),
Julien Desprez0b2263a2019-02-20 10:02:56 -0800108 mAllocationMonitor);
109 } else {
110 // Handle device connected via 'adb connect'
111 testDevice =
112 new RemoteAndroidDevice(
113 idevice,
114 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
115 mAllocationMonitor);
116 testDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE);
117 }
Julien Desprez227af682016-06-01 15:02:58 +0100118 } else if (!checkFrameworkSupport(idevice)) {
Julien Desprez140f2b12018-11-30 13:31:06 -0800119 // Iot device instance tier 1 (no framework support)
120 testDevice =
121 new NativeDevice(
122 idevice,
123 new NativeDeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
124 mAllocationMonitor);
Julien Desprez26bee8d2016-03-29 12:09:48 +0100125 } else {
126 // Default to-go device is Android full stack device.
127 testDevice = new TestDevice(idevice,
128 new DeviceStateMonitor(mDeviceManager, idevice, mFastbootEnabled),
129 mAllocationMonitor);
130 }
Julien Desprez227af682016-06-01 15:02:58 +0100131
Julien Desprez6961b272016-02-01 09:58:23 +0000132 if (idevice instanceof FastbootDevice) {
Julien Desprezf7fed2d2020-05-18 12:40:11 -0700133 testDevice.setDeviceState(TestDeviceState.FASTBOOT);
Julien Desprez6961b272016-02-01 09:58:23 +0000134 } else if (idevice instanceof StubDevice) {
Julien Desprezd5ae9e22016-02-15 18:17:31 +0000135 testDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE);
Julien Desprez6961b272016-02-01 09:58:23 +0000136 }
Julien Desprez26bee8d2016-03-29 12:09:48 +0100137 testDevice.setFastbootEnabled(mFastbootEnabled);
Julien Desprez0a7d67d2016-07-21 16:05:57 +0100138 testDevice.setFastbootPath(mDeviceManager.getFastbootPath());
Julien Desprez6961b272016-02-01 09:58:23 +0000139 return testDevice;
140 }
141
142 /**
Julien Desprez227af682016-06-01 15:02:58 +0100143 * Helper that return true if device has framework support.
144 */
Julien Desprez6f8743f2016-07-29 10:02:01 +0100145 protected boolean checkFrameworkSupport(IDevice idevice) {
Julien Desprez227af682016-06-01 15:02:58 +0100146 if (idevice instanceof StubDevice) {
147 // Assume stub device should go to the default full framework support for
148 // backward compatibility
149 return true;
150 }
151 final long timeout = 60 * 1000;
Julien Desprez227af682016-06-01 15:02:58 +0100152 try {
Julien Desprez493e2642016-08-17 17:49:53 +0100153 for (int i = 0; i < FRAMEWORK_CHECK_MAX_RETRY; i++) {
154 CollectingOutputReceiver receiver = createOutputReceiver();
155 if (!DeviceState.ONLINE.equals(idevice.getState())) {
156 // Device will be 'unavailable' and recreated in DeviceManager so no need to
157 // check.
158 CLog.w("Device state is not Online, assuming Framework support for now.");
159 return true;
160 }
161 String cmd = String.format(CHECK_PM_CMD, EXPECTED_RES);
162 idevice.executeShellCommand(cmd, receiver, timeout, TimeUnit.MILLISECONDS);
163 String output = receiver.getOutput().trim();
164 // It can only be one of the expected output or an exception if device offline
165 // otherwise we retry
166 if (EXPECTED_RES.equals(output)) {
167 return true;
168 }
169 if (output.contains(EXPECTED_ERROR)) {
170 CLog.i("No support for Framework, creating a native device. "
171 + "output: %s", receiver.getOutput());
172 return false;
173 }
174 getRunUtil().sleep(FRAMEWORK_CHECK_SLEEP_MS);
Julien Desprez895e4b12016-08-01 09:44:37 +0100175 }
Julien Desprez493e2642016-08-17 17:49:53 +0100176 CLog.w("Could not determine the framework support for '%s' after retries, assuming "
177 + "framework support.", idevice.getSerialNumber());
Julien Desprez227af682016-06-01 15:02:58 +0100178 } catch (TimeoutException | AdbCommandRejectedException | ShellCommandUnresponsiveException
179 | IOException e) {
Julien Desprez895e4b12016-08-01 09:44:37 +0100180 CLog.w("Exception during checkFrameworkSupport, assuming True: '%s' with device: %s",
181 e.getMessage(), idevice.getSerialNumber());
Julien Desprez227af682016-06-01 15:02:58 +0100182 CLog.e(e);
183 }
184 // We default to support for framework to get same behavior as before.
185 return true;
186 }
187
Julien Desprez0b2263a2019-02-20 10:02:56 -0800188 /** Return the default {@link IRunUtil} instance. */
189 @VisibleForTesting
Julien Desprez493e2642016-08-17 17:49:53 +0100190 protected IRunUtil getRunUtil() {
191 return RunUtil.getDefault();
192 }
193
194 /**
Julien Desprez0b2263a2019-02-20 10:02:56 -0800195 * Return true if we are currently running in a remote environment. This will alter the device
196 * behavior.
Julien Desprez6f8743f2016-07-29 10:02:01 +0100197 */
Julien Desprez0b2263a2019-02-20 10:02:56 -0800198 @VisibleForTesting
199 protected boolean isRemoteEnvironment() {
Julien Desprez83977b92019-07-19 09:37:07 -0700200 return SystemUtil.isRemoteEnvironment();
Julien Desprez0b2263a2019-02-20 10:02:56 -0800201 }
202
203 /** Create a {@link CollectingOutputReceiver}. */
204 @VisibleForTesting
Julien Desprez6f8743f2016-07-29 10:02:01 +0100205 protected CollectingOutputReceiver createOutputReceiver() {
206 return new CollectingOutputReceiver();
207 }
208
209 /**
Julien Desprez6961b272016-02-01 09:58:23 +0000210 * {@inheritDoc}
211 */
212 @Override
213 public void setFastbootEnabled(boolean enable) {
214 mFastbootEnabled = enable;
215 }
Julien Desprez59e0e3a2016-06-13 11:07:22 +0100216
217 /**
218 * Helper to device if it's a serial from a remotely connected device.
219 * serial format of tcp device is <ip or locahost>:<port>
220 */
221 protected boolean isTcpDeviceSerial(String serial) {
222 final String remotePattern = IPADDRESS_PATTERN + "(:)([0-9]{2,5})(\\b)";
223 Pattern pattern = Pattern.compile(remotePattern);
224 Matcher match = pattern.matcher(serial.trim());
225 if (match.find()) {
226 return true;
227 }
228 return false;
229 }
Julien Desprez6961b272016-02-01 09:58:23 +0000230}