-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
375 additions
and
1 deletion.
There are no files selected for viewing
67 changes: 67 additions & 0 deletions
67
.../google/devtools/mobileharness/api/devicemanager/detector/AndroidJitEmulatorDetector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.devtools.mobileharness.api.devicemanager.detector; | ||
|
||
import static com.google.common.collect.ImmutableList.toImmutableList; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.AndroidEmulatorType; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.DetectionResult; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.DetectionResult.DetectionType; | ||
import com.google.devtools.mobileharness.shared.util.flags.Flags; | ||
import javax.annotation.Nullable; | ||
|
||
/** Detector for Android JIT emulators. */ | ||
public final class AndroidJitEmulatorDetector implements Detector { | ||
/** Initialized in {@link #precondition()}. */ | ||
@Nullable private volatile ImmutableList<String> emulatorIds; | ||
|
||
// Acloud creates cuttlefish emulator with port 6520 + index, where index is instance id minus | ||
// one. Example: "acloud create --local-instance 1" will create a local emulator with port 6520. | ||
// And instance 2 will be 6521, so on and so forth. | ||
private static final int EMULATOR_BASE_PORT = 6520; | ||
|
||
public AndroidJitEmulatorDetector() {} | ||
|
||
/** | ||
* Precondition of the detector. | ||
* | ||
* @return whether the precondition meets | ||
*/ | ||
@Override | ||
public boolean precondition() { | ||
int emulatorNumber = Flags.instance().androidJitEmulatorNum.getNonNull(); | ||
ImmutableList.Builder<String> emulatorIdsBuilder = ImmutableList.builder(); | ||
for (int i = 0; i < emulatorNumber; i++) { | ||
emulatorIdsBuilder.add("0.0.0.0:" + (i + EMULATOR_BASE_PORT)); | ||
} | ||
emulatorIds = emulatorIdsBuilder.build(); | ||
return emulatorNumber > 0; | ||
} | ||
|
||
/** | ||
* Detects the Android JIT emulators. | ||
* | ||
* @return the detection result of the Android JIT emulators | ||
*/ | ||
@Override | ||
public ImmutableList<DetectionResult> detectDevices() { | ||
return emulatorIds.stream() | ||
.map(id -> DetectionResult.of(id, DetectionType.EMULATOR, AndroidEmulatorType.JIT_EMULATOR)) | ||
.collect(toImmutableList()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
...gle/devtools/mobileharness/api/devicemanager/dispatcher/AndroidJitEmulatorDispatcher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.devtools.mobileharness.api.devicemanager.dispatcher; | ||
|
||
import static com.google.common.collect.ImmutableMap.toImmutableMap; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.AndroidEmulatorType; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.DetectionResult; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.DetectionResult.DetectionType; | ||
import com.google.devtools.mobileharness.api.devicemanager.detector.model.DetectionResults; | ||
import com.google.devtools.mobileharness.api.devicemanager.dispatcher.model.DispatchResult.DispatchType; | ||
import com.google.devtools.mobileharness.api.devicemanager.dispatcher.model.DispatchResults; | ||
import com.google.devtools.mobileharness.api.devicemanager.dispatcher.util.DeviceIdGenerator; | ||
import com.google.devtools.mobileharness.api.model.lab.DeviceId; | ||
|
||
/** Dispatcher for Android JIT Emulator devices. */ | ||
public final class AndroidJitEmulatorDispatcher implements Dispatcher { | ||
private final DeviceIdGenerator deviceIdGenerator; | ||
|
||
public AndroidJitEmulatorDispatcher() { | ||
this(new DeviceIdGenerator()); | ||
} | ||
|
||
@VisibleForTesting | ||
AndroidJitEmulatorDispatcher(DeviceIdGenerator deviceIdGenerator) { | ||
this.deviceIdGenerator = deviceIdGenerator; | ||
} | ||
|
||
@Override | ||
public ImmutableMap<String, DispatchType> dispatchDevices( | ||
DetectionResults detectionResults, DispatchResults dispatchResults) { | ||
return detectionResults | ||
.getByTypeAndDetail(DetectionType.EMULATOR, AndroidEmulatorType.JIT_EMULATOR) | ||
.stream() | ||
.collect(toImmutableMap(DetectionResult::deviceControlId, s -> DispatchType.LIVE)); | ||
} | ||
|
||
@Override | ||
public DeviceId generateDeviceId(String deviceControlId) { | ||
return deviceIdGenerator.getAndroidDeviceId(deviceControlId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
src/java/com/google/wireless/qa/mobileharness/shared/api/device/AndroidJitEmulator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.wireless.qa.mobileharness.shared.api.device; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.base.Ascii; | ||
import com.google.common.flogger.FluentLogger; | ||
import com.google.devtools.mobileharness.api.model.error.MobileHarnessException; | ||
import com.google.devtools.mobileharness.api.model.proto.Device.PostTestDeviceOp; | ||
import com.google.devtools.mobileharness.infra.controller.device.config.ApiConfig; | ||
import com.google.devtools.mobileharness.platform.android.sdktool.adb.AndroidAdbUtil; | ||
import com.google.devtools.mobileharness.platform.android.sdktool.adb.AndroidProperty; | ||
import com.google.devtools.mobileharness.shared.util.command.Command; | ||
import com.google.devtools.mobileharness.shared.util.command.CommandExecutor; | ||
import com.google.devtools.mobileharness.shared.util.command.Timeout; | ||
import com.google.devtools.mobileharness.shared.util.file.local.LocalFileUtil; | ||
import com.google.devtools.mobileharness.shared.util.flags.Flags; | ||
import com.google.errorprone.annotations.CanIgnoreReturnValue; | ||
import com.google.wireless.qa.mobileharness.shared.api.validator.ValidatorFactory; | ||
import com.google.wireless.qa.mobileharness.shared.model.job.TestInfo; | ||
import java.nio.file.Path; | ||
import java.time.Duration; | ||
import javax.annotation.Nullable; | ||
|
||
/** Android emulator device class. This emulator is created by acloud on demand of test requests. */ | ||
public class AndroidJitEmulator extends AndroidDevice { | ||
private static final FluentLogger logger = FluentLogger.forEnclosingClass(); | ||
|
||
public static final String JIT_EMULATOR_IMAGE_ZIP = "JIT_EMULATOR_IMAGE_ZIP"; | ||
public static final String JIT_EMULATOR_HOST_PACKAGE = "JIT_EMULATOR_HOST_PACKAGE"; | ||
public static final String JIT_EMULATOR_ACLOUD = "JIT_EMULATOR_ACLOUD"; | ||
|
||
// TODO: Move to a shared class. | ||
public static final int EMULATOR_BASE_PORT = 6520; | ||
public static final int EMULATOR_INSTANCE_ID_BASE = 1; | ||
|
||
private final String deviceId; | ||
private final AndroidAdbUtil androidAdbUtil; | ||
private final LocalFileUtil localFileUtil; | ||
private final CommandExecutor commandExecutor; | ||
|
||
public AndroidJitEmulator(String deviceId) { | ||
this( | ||
deviceId, | ||
ApiConfig.getInstance(), | ||
new ValidatorFactory(), | ||
new CommandExecutor(), | ||
new AndroidAdbUtil(), | ||
new LocalFileUtil()); | ||
} | ||
|
||
@VisibleForTesting | ||
AndroidJitEmulator( | ||
String deviceId, | ||
@Nullable ApiConfig apiConfig, | ||
@Nullable ValidatorFactory validatorFactory, | ||
CommandExecutor commandExecutor, | ||
AndroidAdbUtil androidAdbUtil, | ||
LocalFileUtil localFileUtil) { | ||
super(deviceId, apiConfig, validatorFactory); | ||
this.deviceId = deviceId; | ||
this.commandExecutor = commandExecutor; | ||
this.androidAdbUtil = androidAdbUtil; | ||
this.localFileUtil = localFileUtil; | ||
} | ||
|
||
@Override | ||
public void setUp() throws MobileHarnessException, InterruptedException { | ||
logger.atInfo().log("JIT emulator start setup. %s", deviceId); | ||
addDimension(Ascii.toLowerCase(AndroidProperty.ABILIST.name()), "x86_64"); | ||
addDimension(Ascii.toLowerCase(AndroidProperty.ABI.name()), "x86_64"); | ||
addSupportedDriver("NoOpDriver"); | ||
addSupportedDriver("AndroidInstrumentation"); | ||
addSupportedDriver("MoblyTest"); | ||
addSupportedDriver("XtsTradefedTest"); | ||
|
||
addSupportedDecorator("AndroidHdVideoDecorator"); | ||
addSupportedDecorator("AndroidDeviceSettingsDecorator"); | ||
addSupportedDecorator("AndroidAdbShellDecorator"); | ||
|
||
addSupportedDeviceType(AndroidJitEmulator.class.getSimpleName()); | ||
addSupportedDeviceType(AndroidDevice.class.getSimpleName()); | ||
basicAndroidDecoratorConfiguration(); | ||
|
||
logger.atInfo().log("JIT emulator %s is Ready", deviceId); | ||
} | ||
|
||
@Override | ||
public void preRunTest(TestInfo testInfo) throws MobileHarnessException, InterruptedException { | ||
String imgZip = testInfo.jobInfo().files().getSingle("device"); | ||
String hostPkg = testInfo.jobInfo().files().getSingle("cvd-host_package.tar.gz"); | ||
Path imageDir = Path.of(testInfo.getTmpFileDir()).resolve("image_dir"); | ||
localFileUtil.prepareDir(imageDir); | ||
|
||
Path hostPkgDir = Path.of(testInfo.getTmpFileDir()).resolve("cvd-host_package"); | ||
String acloudPath = Flags.instance().acloudPath.getNonNull(); | ||
localFileUtil.prepareDir(hostPkgDir); | ||
localFileUtil.unzipFile(imgZip, imageDir.toString()); | ||
|
||
Command unzipHostPkgCmd = Command.of("tar", "-xvzf", hostPkg, "-C", hostPkgDir.toString()); | ||
String unzipHostPkgOutput = commandExecutor.run(unzipHostPkgCmd); | ||
logger.atFine().log("unzipHostPkgOutput: %s", unzipHostPkgOutput); | ||
|
||
localFileUtil.grantFileOrDirFullAccessRecursively(imageDir); | ||
localFileUtil.grantFileOrDirFullAccessRecursively(hostPkgDir); | ||
localFileUtil.grantFileOrDirFullAccess(acloudPath); | ||
|
||
Command command = | ||
Command.of( | ||
acloudPath, | ||
"create", | ||
"--local-instance", | ||
getInstanceId(), | ||
"--local-image", | ||
imageDir.toString(), | ||
"--local-tool", | ||
hostPkgDir.toString(), | ||
"--yes", | ||
"--no-autoconnect", | ||
"--skip-pre-run-check") | ||
.timeout(Timeout.fixed(Duration.ofMinutes(2))); | ||
String output = commandExecutor.run(command); | ||
logger.atInfo().log("acloud create output: %s", output); | ||
String deviceIpAddress = getDeviceId(); | ||
// Attempt to establish an ADB connection to a device's IP address, with retry mechanism | ||
androidAdbUtil.connect(deviceIpAddress); | ||
} | ||
|
||
@CanIgnoreReturnValue | ||
@Override | ||
public PostTestDeviceOp postRunTest(TestInfo testInfo) | ||
throws MobileHarnessException, InterruptedException { | ||
String acloudPath = Flags.instance().acloudPath.getNonNull(); | ||
localFileUtil.grantFileOrDirFullAccess(acloudPath); | ||
Command command = | ||
Command.of(acloudPath, "delete", "--instance-names", "local-instance-" + getInstanceId()); | ||
String output = commandExecutor.run(command); | ||
logger.atInfo().log("acloud delete output: %s", output); | ||
return PostTestDeviceOp.NONE; | ||
} | ||
|
||
@Override | ||
public boolean canReboot() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void reboot() throws MobileHarnessException, InterruptedException { | ||
logger.atSevere().log("Unexpected attempt to reboot a non-rebootable device"); | ||
} | ||
|
||
@Override | ||
public boolean isRooted() { | ||
// We suppose all emulators are rooted. | ||
return true; | ||
} | ||
|
||
// TODO: Move instance id logic to a shared class to share with | ||
// AndroidJitEmulatorDetector. | ||
private String getInstanceId() { | ||
return String.valueOf( | ||
Integer.parseInt(getDeviceId().substring(getDeviceId().indexOf(':') + 1)) | ||
- EMULATOR_BASE_PORT | ||
+ EMULATOR_INSTANCE_ID_BASE); | ||
} | ||
} |
Oops, something went wrong.