use of com.android.tools.build.bundletool.device.PackagesParser.InstalledPackageInfo in project bundletool by google.
the class InstallMultiApksCommand method extractApkListFromApks.
/**
* Extracts the apk/apex files that will be installed from a given .apks.
*/
private static ImmutableList<PackagePathVersion> extractApkListFromApks(DeviceSpec deviceSpec, PackagePathVersion apksArchive, Optional<InstalledPackageInfo> installedPackage, TempDirectory tempDirectory) {
logger.info(String.format("Extracting package '%s'", apksArchive.getPackageName()));
try {
Path output = tempDirectory.getPath().resolve(apksArchive.getPackageName());
Files.createDirectory(output);
ExtractApksCommand.Builder extractApksCommand = ExtractApksCommand.builder().setApksArchivePath(apksArchive.getPath()).setDeviceSpec(deviceSpec).setOutputDirectory(output);
ImmutableList<Path> extractedPaths = fixExtension(extractApksCommand.build().execute(), installedPackage.map(InstalledPackageInfo::isApex).orElse(false));
return extractedPaths.stream().map(path -> PackagePathVersion.create(path, apksArchive.getPackageName(), apksArchive.getVersionCode())).collect(toImmutableList());
} catch (IncompatibleDeviceException e) {
logger.warning(String.format("Package '%s' is not supported by the attached device (SDK version %d). Skipping.", apksArchive.getPackageName(), deviceSpec.getSdkVersion()));
return ImmutableList.of();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
use of com.android.tools.build.bundletool.device.PackagesParser.InstalledPackageInfo in project bundletool by google.
the class InstallMultiApksCommand method getPackagesInstalledOnDevice.
private static ImmutableMap<String, InstalledPackageInfo> getPackagesInstalledOnDevice(Device device) {
// List standard packages (excluding apex)
ImmutableList<String> listPackagesOutput = new AdbShellCommandTask(device, "pm list packages --show-versioncode").execute();
// List .apex packages.
ImmutableList<String> listApexPackagesOutput = new AdbShellCommandTask(device, "pm list packages --apex-only --show-versioncode").execute();
ImmutableSet<InstalledPackageInfo> installedApks = new PackagesParser(/* isApex= */
false).parse(listPackagesOutput);
ImmutableSet<InstalledPackageInfo> installedApexPackages = new PackagesParser(/* isApex= */
true).parse(listApexPackagesOutput);
return Streams.concat(installedApks.stream(), installedApexPackages.stream()).collect(toImmutableMap(InstalledPackageInfo::getPackageName, installedPackageInfo -> installedPackageInfo));
}
use of com.android.tools.build.bundletool.device.PackagesParser.InstalledPackageInfo in project bundletool by google.
the class InstallMultiApksCommand method shouldInstall.
/**
* The package should be installed if:
*
* <ul>
* <li>If it is not already present on the device and --update-only is not set, or
* <li>The installable version has a equal or higher version code than the one already
* installed.
* </ul>
*/
private boolean shouldInstall(PackagePathVersion apk, ImmutableMap<String, InstalledPackageInfo> existingPackages) {
if (getUpdateOnly() && !existingPackages.containsKey(apk.getPackageName())) {
logger.info(String.format("Package '%s' not present on device, skipping due to --%s.", apk.getPackageName(), UPDATE_ONLY_FLAG.getName()));
return false;
}
if (!existingPackages.containsKey(apk.getPackageName())) {
return true;
}
InstalledPackageInfo existingPackage = existingPackages.get(apk.getPackageName());
if (existingPackage.getVersionCode() <= apk.getVersionCode()) {
return true;
}
// If the user is attempting to install a mixture of lower and higher version .apks, that
// likely indicates something is wrong.
logger.warning(String.format("A higher version of package '%s' (%d vs %d) is already present on device," + " skipping.", apk.getPackageName(), apk.getVersionCode(), existingPackage.getVersionCode()));
return false;
}
use of com.android.tools.build.bundletool.device.PackagesParser.InstalledPackageInfo in project bundletool by google.
the class InstallMultiApksCommand method execute.
public void execute() throws TimeoutException, IOException {
validateInput();
AdbServer adbServer = getAdbServer();
adbServer.init(getAdbPath());
try (TempDirectory tempDirectory = new TempDirectory()) {
DeviceAnalyzer deviceAnalyzer = new DeviceAnalyzer(adbServer);
DeviceSpec deviceSpec = deviceAnalyzer.getDeviceSpec(getDeviceId());
Device device = deviceAnalyzer.getAndValidateDevice(getDeviceId());
if (getTimeout().isPresent() && !device.getVersion().isGreaterOrEqualThan(Versions.ANDROID_S_API_VERSION)) {
throw InvalidCommandException.builder().withInternalMessage("'%s' flag is supported for Android 12+ devices.", TIMEOUT_MILLIS_FLAG.getName()).build();
}
Path aapt2Dir = tempDirectory.getPath().resolve("aapt2");
Files.createDirectory(aapt2Dir);
Supplier<Aapt2Command> aapt2CommandSupplier = Suppliers.memoize(() -> getOrExtractAapt2Command(aapt2Dir));
ImmutableMap<String, InstalledPackageInfo> existingPackages = getPackagesInstalledOnDevice(device);
ImmutableList<PackagePathVersion> installableApksFilesWithBadgingInfo = getActualApksPaths(tempDirectory).stream().flatMap(apksArchivePath -> stream(apksWithPackageName(apksArchivePath, deviceSpec, aapt2CommandSupplier))).filter(apks -> shouldInstall(apks, existingPackages)).collect(toImmutableList());
ImmutableList<PackagePathVersion> apkFilesToInstall = uniqueApksByPackageName(installableApksFilesWithBadgingInfo).stream().flatMap(apks -> extractApkListFromApks(deviceSpec, apks, Optional.ofNullable(existingPackages.get(apks.getPackageName())), tempDirectory).stream()).collect(toImmutableList());
ImmutableListMultimap<String, String> apkToInstallByPackage = apkFilesToInstall.stream().collect(toImmutableListMultimap(PackagePathVersion::getPackageName, packagePathVersion -> packagePathVersion.getPath().toAbsolutePath().toString()));
if (apkFilesToInstall.isEmpty()) {
logger.warning("No packages found to install! Exiting...");
return;
}
AdbCommand adbCommand = getOrCreateAdbCommand();
ImmutableList<String> commandResults = adbCommand.installMultiPackage(apkToInstallByPackage, getStaged(), getEnableRollback(), getTimeout(), getDeviceId());
logger.info(String.format("Output:\n%s", String.join("\n", commandResults)));
logger.info("Please reboot device to complete installation.");
}
}
Aggregations