usecrate::capabilities::AndroidOptions; use mozdevice::{AndroidStorage, Device, Host, RemoteMetadata, UnixPathBuf}; use mozprofile::profile::Profile; use serde::Serialize; use serde_yaml::{Mapping, Value}; use std::fs::File; use std::io; use std::path::PathBuf; use std::time; use thiserror::Error; use webdriver::error::{ErrorStatus, WebDriverError};
// TODO: avoid port clashes across GeckoView-vehicles. // For now, we always use target port 2829, leading to issues like bug 1533704. const MARIONETTE_TARGET_PORT: u16 = 2829;
const CONFIG_FILE_HEADING: &str = r#"## GeckoView configuration YAML ## ## Auto-generated by geckodriver. ## See https://mozilla.github.io/geckoview/consumer/docs/automation. "#;
impl AndroidHandler { pubfn new(
options: &AndroidOptions,
marionette_host_port: u16,
websocket_port: Option<u16>,
) -> Result<AndroidHandler> { // We need to push profile.pathbuf to a safe space on the device. // Make it per-Android package to avoid clashes and confusion. // This naming scheme follows GeckoView's configuration file naming scheme, // see bug 1533385.
// Set up port forwarding for Marionette.
debug!( "Start forwarding Marionette port ({} -> {})",
marionette_host_port, MARIONETTE_TARGET_PORT
);
device.forward_port(marionette_host_port, MARIONETTE_TARGET_PORT)?;
iflet Some(port) = websocket_port { // Set up port forwarding for WebSocket connections (WebDriver BiDi, and CDP).
debug!("Start forwarding WebSocket port ({} -> {})", port, port);
device.forward_port(port, port)?;
}
let test_root = match device.storage {
AndroidStorage::App => {
device.run_as_package = Some(options.package.to_owned()); letmut buf = UnixPathBuf::from("/data/data");
buf.push(&options.package);
buf.push("test_root");
buf
}
AndroidStorage::Internal => UnixPathBuf::from("/data/local/tmp/test_root"),
AndroidStorage::Sdcard => { // We need to push the profile to a location on the device that can also // be read and write by the application, and works for unrooted devices. // The only location that meets this criteria is under: // $EXTERNAL_STORAGE/Android/data/%options.package%/files let response = device.execute_host_shell_command("echo $EXTERNAL_STORAGE")?; letmut buf = UnixPathBuf::from(response.trim_end_matches('\n'));
buf.push("Android/data");
buf.push(&options.package);
buf.push("files/test_root");
buf
}
};
// Check if the specified package is installed let response =
device.execute_host_shell_command(&format!("pm list packages {}", &options.package))?; letmut packages = response
.trim()
.split_terminator('\n')
.filter(|line| line.starts_with("package:"))
.map(|line| line.rsplit(':').next().expect("Package name found")); if !packages.any(|x| x == options.package.as_str()) { return Err(AndroidError::PackageNotFound(options.package.clone()));
}
let config = UnixPathBuf::from(format!( "/data/local/tmp/{}-geckoview-config.yaml",
&options.package
));
// If activity hasn't been specified default to the main activity of the package let activity = match options.activity {
Some(ref activity) => activity.clone(),
None => { let response = device.execute_host_shell_command(&format!( "cmd package resolve-activity --brief {}",
&options.package
))?; let activities = response
.split_terminator('\n')
.filter(|line| line.starts_with(&options.package))
.map(|line| line.rsplit('/').next().unwrap())
.collect::<Vec<&str>>(); if activities.is_empty() { return Err(AndroidError::ActivityNotFound(options.package.clone()));
}
activities[0].to_owned()
}
};
let process = AndroidProcess::new(device, options.package.clone(), activity)?;
// These permissions, at least, are required to read profiles in /mnt/sdcard. for perm in &["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"] { self.process.device.execute_host_shell_command(&format!( "pm grant {} android.permission.{}",
&self.process.package, perm
))?;
}
// Make sure to create the test root. self.process.device.create_dir(&self.test_root)?; self.process.device.chmod(&self.test_root, "777", true)?;
// Replace the profile self.process.device.remove(&self.profile)?; self.process
.device
.push_dir(&profile.path, &self.profile, 0o777)?;
let contents = self.generate_config_file(args, env)?;
debug!("Content of generated GeckoView config file:\n{}", contents); let reader = &mut io::BufReader::new(contents.as_bytes());
// Tell GeckoView to read configuration even when `android:debuggable="false"`. self.process.device.execute_host_shell_command(&format!( "am set-debug-app --persistent {}", self.process.package
))?;
Ok(())
}
pubfn launch(&self) -> Result<()> { // TODO: Remove the usage of intent arguments once Fennec is no longer // supported. Packages which are using GeckoView always read the arguments // via the YAML configuration file. letmut intent_arguments = self
.options
.intent_arguments
.clone()
.unwrap_or_else(|| Vec::with_capacity(3));
intent_arguments.push("--es".to_owned());
intent_arguments.push("args".to_owned());
intent_arguments.push(format!("--marionette --profile {}", self.profile.display()));
#[cfg(test)] mod test { // To successfully run those tests the geckoview_example package needs to // be installed on the device or emulator. After setting up the build // environment (https://mzl.la/3muLv5M), the following mach commands have to // be executed: // // $ ./mach build && ./mach install // // Currently the mozdevice API is not safe for multiple requests at the same // time. It is recommended to run each of the unit tests on its own. Also adb // specific tests cannot be run in CI yet. To check those locally, also run // the ignored tests. // // Use the following command to accomplish that: // // $ cargo test -- --ignored --test-threads=1
usecrate::android::AndroidHandler; usecrate::capabilities::AndroidOptions; use mozdevice::{AndroidStorage, AndroidStorageInput, UnixPathBuf};
fn run_handler_storage_test(package: &str, storage: AndroidStorageInput) { let options = AndroidOptions::new(package.to_owned(), storage); let handler = AndroidHandler::new(&options, 4242, None).expect("has valid Android handler");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.