mirror of
https://github.com/chenxiaolong/avbroot.git
synced 2026-07-03 14:05:11 +02:00
Merge pull request #246 from chenxiaolong/remove_modules
Remove oemunlockonboot module
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
---
|
||||
name: Modules
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
jobs:
|
||||
build:
|
||||
name: Build modules
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# For git describe
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get version
|
||||
id: get_version
|
||||
shell: bash
|
||||
run: |
|
||||
echo -n 'version=' >> "${GITHUB_OUTPUT}"
|
||||
git describe --always \
|
||||
| sed -E "s/^v//g;s/([^-]*-g)/r\1/;s/-/./g" \
|
||||
>> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Build modules
|
||||
run: cargo xtask modules -a
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: avbroot-modules-${{ steps.get_version.outputs.version }}
|
||||
path: modules/dist/
|
||||
Generated
-60
@@ -728,12 +728,6 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "human-sort"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "140a09c9305e6d5e557e2ed7cbc68e05765a7d4213975b87cb04920689cc6219"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
@@ -1433,15 +1427,6 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scrypt"
|
||||
version = "0.11.0"
|
||||
@@ -1731,16 +1716,6 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@@ -1759,37 +1734,6 @@ dependencies = [
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -1961,12 +1905,8 @@ version = "3.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"human-sort",
|
||||
"regex",
|
||||
"tempfile",
|
||||
"toml_edit",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -33,11 +33,7 @@ avbroot applies the following patches to the partition images:
|
||||
|
||||
Repeat: **_ALWAYS leave `OEM unlocking` enabled if rooted._**
|
||||
|
||||
* Any operation that causes an improperly-signed boot image to be flashed will result in the device being unbootable and unrecoverable without unlocking the bootloader again (and thus, triggering a data wipe). This includes:
|
||||
|
||||
* Performing a unpatched A/B OTA update while booted into Android via the OS' default updater. This can be blocked via a Magisk/KernelSU module (see: [Blocking A/B OTA Updates](#blocking-ab-ota-updates)).
|
||||
|
||||
* The `Direct install` method for updating Magisk. Magisk updates **must** be done by repatching the OTA, not via the app.
|
||||
* Any operation that causes an improperly-signed boot image to be flashed will result in the device being unbootable and unrecoverable without unlocking the bootloader again (and thus, triggering a data wipe). This includes the `Direct install` method for updating Magisk. Magisk updates **must** be done by repatching the OTA, not via the app.
|
||||
|
||||
If the boot image is ever modified, **do not reboot**. [Open an issue](https://github.com/chenxiaolong/avbroot/issues/new) for support and be very clear about what steps were done that lead to the situation. If Android is still running and root access works, it might be possible to recover without wiping and starting over.
|
||||
|
||||
@@ -184,12 +180,10 @@ If you lose your AVB or OTA signing key, you will no longer be able to sign new
|
||||
|
||||
Remember: **Do not uncheck `OEM unlocking`!**
|
||||
|
||||
**WARNING**: If you are flashing CalyxOS, the setup wizard will [automatically turn off the `OEM unlocking` switch](https://github.com/CalyxOS/platform_packages_apps_SetupWizard/blob/7d2df25cedcbff83ddb608e628f9d97b38259c26/src/org/lineageos/setupwizard/SetupWizardApp.java#L135-L140). Make sure to manually reenable it again from Android's developer settings. Consider using [avbroot's `oemunlockonboot` Magisk module](#oemunlockonboot-enable-oem-unlocking-on-every-boot) to automatically ensure OEM unlocking is enabled on every boot.
|
||||
**WARNING**: If you are flashing CalyxOS, the setup wizard will [automatically turn off the `OEM unlocking` switch](https://github.com/CalyxOS/platform_packages_apps_SetupWizard/blob/7d2df25cedcbff83ddb608e628f9d97b38259c26/src/org/lineageos/setupwizard/SetupWizardApp.java#L135-L140). Make sure to manually reenable it again from Android's developer settings. Consider using the [`OEMUnlockOnBoot` module](https://github.com/chenxiaolong/OEMUnlockOnBoot) to automatically ensure OEM unlocking is enabled on every boot.
|
||||
|
||||
8. That's it! To install future OS, Magisk, or KernelSU updates, see the [next section](#updates).
|
||||
|
||||
For extra safety, consider flashing [avbroot's Magisk/KernelSU modules](#avbroot-modules).
|
||||
|
||||
## Updates
|
||||
|
||||
Updates to Android, Magisk, and KernelSU are all done the same way by patching (or repatching) the OTA.
|
||||
@@ -251,16 +245,6 @@ To safely use Repair Mode:
|
||||
|
||||
Because the unrooting and rooting are done by flashing OTAs, the device's data will not be wiped.
|
||||
|
||||
## avbroot modules
|
||||
|
||||
avbroot's Magisk/KernelSU modules can be downloaded from the [releases page](https://github.com/chenxiaolong/avbroot/releases).
|
||||
|
||||
### `oemunlockonboot`: Enable OEM unlocking on every boot
|
||||
|
||||
To help reduce the risk of OEM unlocking being accidentally disabled (or intentionally disabled as part of some OS' initial setup wizard), this module will attempt to enable the OEM unlocking option on every boot.
|
||||
|
||||
The logs for this module can be found at `/data/local/tmp/avbroot_oem_unlock.log`.
|
||||
|
||||
## Magisk preinit device
|
||||
|
||||
Magisk versions 25211 and newer require a writable partition for storing custom SELinux rules that need to be accessed during early boot stages. This can only be determined on a real device, so avbroot requires the partition to be explicitly specified via `--magisk-preinit-device <name>`. To find the partition name:
|
||||
@@ -437,14 +421,6 @@ Debug builds work too, but they will run significantly slower (in the sha256 com
|
||||
|
||||
By default, the executable links to the system's bzip2 and liblzma libraries, which are the only external libraries avbroot depends on. To compile and statically link these two libraries, pass in `--features static`.
|
||||
|
||||
To build avbroot's modules from source, run:
|
||||
|
||||
```bash
|
||||
cargo xtask modules -a
|
||||
```
|
||||
|
||||
This requires Java and the Android SDK to be installed. The `ANDROID_HOME` environment variable must be set to the Android SDK path.
|
||||
|
||||
## Verifying digital signatures
|
||||
|
||||
First, save the public key to a file listing the keys to be trusted. This is the same key listed in [the author's profile](https://github.com/chenxiaolong/).
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/sbin/sh
|
||||
|
||||
#################
|
||||
# Initialization
|
||||
#################
|
||||
|
||||
umask 022
|
||||
|
||||
# echo before loading util_functions
|
||||
ui_print() { echo "$1"; }
|
||||
|
||||
require_new_magisk() {
|
||||
ui_print "*******************************"
|
||||
ui_print " Please install Magisk v20.4+! "
|
||||
ui_print "*******************************"
|
||||
exit 1
|
||||
}
|
||||
|
||||
#########################
|
||||
# Load util_functions.sh
|
||||
#########################
|
||||
|
||||
OUTFD=$2
|
||||
ZIPFILE=$3
|
||||
|
||||
mount /data 2>/dev/null
|
||||
|
||||
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
|
||||
. /data/adb/magisk/util_functions.sh
|
||||
[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
|
||||
|
||||
install_module
|
||||
exit 0
|
||||
@@ -1 +0,0 @@
|
||||
#MAGISK
|
||||
@@ -1,83 +0,0 @@
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Process;
|
||||
import android.system.ErrnoException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@SuppressLint({"DiscouragedPrivateApi", "PrivateApi", "SoonBlockedPrivateApi"})
|
||||
public class Main {
|
||||
private static final int GET_SERVICE_ATTEMPTS = 30;
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static IInterface getService(Class<?> interfaceClass, String serviceName) throws Exception {
|
||||
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
|
||||
Method getService = serviceManager.getDeclaredMethod("getService", String.class);
|
||||
|
||||
Class<?> stub = Class.forName(interfaceClass.getCanonicalName() + "$Stub");
|
||||
Method asInterface = stub.getDeclaredMethod("asInterface", IBinder.class);
|
||||
|
||||
// ServiceManager.waitForService() tries to start the service, which we want to avoid to be
|
||||
// 100% sure we're not disrupting the boot flow.
|
||||
for (int attempt = 1; attempt <= GET_SERVICE_ATTEMPTS; ++attempt) {
|
||||
IBinder iBinder = (IBinder) getService.invoke(null, serviceName);
|
||||
if (iBinder != null) {
|
||||
return (IInterface) asInterface.invoke(null, iBinder);
|
||||
}
|
||||
|
||||
if (attempt < GET_SERVICE_ATTEMPTS) {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
"Service " + serviceName + " not found after " + GET_SERVICE_ATTEMPTS + " attempts");
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static void unlock() throws Exception {
|
||||
Class<?> iOemLockService = Class.forName("android.service.oemlock.IOemLockService");
|
||||
IInterface iFace = getService(iOemLockService, "oem_lock");
|
||||
|
||||
Method setOemUnlockAllowedByUser = iOemLockService.getDeclaredMethod("setOemUnlockAllowedByUser", boolean.class);
|
||||
Method isOemUnlockAllowedByUser = iOemLockService.getDeclaredMethod("isOemUnlockAllowedByUser");
|
||||
|
||||
Boolean unlockAllowed = (Boolean) isOemUnlockAllowedByUser.invoke(iFace);
|
||||
if (unlockAllowed) {
|
||||
System.out.println("OEM unlocking already enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Enabling OEM unlocking");
|
||||
setOemUnlockAllowedByUser.invoke(iFace, true);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ConstantConditions", "JavaReflectionMemberAccess"})
|
||||
private static void switchToSystemUid() throws Exception {
|
||||
if (Process.myUid() != Process.SYSTEM_UID) {
|
||||
Method setUid = Process.class.getDeclaredMethod("setUid", int.class);
|
||||
int errno = (int) setUid.invoke(null, Process.SYSTEM_UID);
|
||||
|
||||
if (errno != 0) {
|
||||
throw new Exception("Failed to switch to SYSTEM (" + Process.SYSTEM_UID + ") user",
|
||||
new ErrnoException("setuid", errno));
|
||||
}
|
||||
if (Process.myUid() != Process.SYSTEM_UID) {
|
||||
throw new IllegalStateException("UID didn't actually change: " +
|
||||
Process.myUid() + " != " + Process.SYSTEM_UID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
switchToSystemUid();
|
||||
unlock();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to enable OEM unlocking");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
id=com.chiller3.avbroot.oemunlockonboot
|
||||
name=oemunlockonboot
|
||||
version=v3.0.0
|
||||
versionCode=196608
|
||||
author=chenxiaolong
|
||||
description=Enable OEM unlocking on every boot
|
||||
@@ -1,20 +0,0 @@
|
||||
exec >/data/local/tmp/avbroot_oem_unlock.log 2>&1
|
||||
|
||||
mod_dir=${0%/*}
|
||||
|
||||
header() {
|
||||
echo "----- ${*} -----"
|
||||
}
|
||||
|
||||
header Environment
|
||||
echo "Timestamp: $(date)"
|
||||
echo "Script: ${0}"
|
||||
echo "UID/GID/Context: $(id)"
|
||||
|
||||
header Enable OEM unlocking
|
||||
CLASSPATH="${mod_dir}/classes.dex" app_process / Main &
|
||||
pid=${!}
|
||||
wait "${pid}"
|
||||
echo "Exit status: ${?}"
|
||||
echo "Logcat:"
|
||||
logcat -d --pid "${pid}"
|
||||
@@ -11,14 +11,5 @@ publish = false
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
clap = { version = "4.4.1", features = ["derive"] }
|
||||
human-sort = "0.2.2"
|
||||
regex = { version = "1.9.4", default-features = false, features = ["perf", "std"] }
|
||||
tempfile = "3.8.0"
|
||||
toml_edit = "0.21.0"
|
||||
walkdir = "2.3.3"
|
||||
|
||||
# https://github.com/zip-rs/zip/pull/383
|
||||
[dependencies.zip]
|
||||
git = "https://github.com/chenxiaolong/zip"
|
||||
rev = "989101f9384b9e94e36e6e9e0f51908fdf98bde6"
|
||||
default-features = false
|
||||
|
||||
+1
-12
@@ -8,7 +8,7 @@ To update the project version, run:
|
||||
cargo xtask set-version -V <version>
|
||||
```
|
||||
|
||||
This will update the main [`Cargo.toml`](../Cargo.toml) and each module's `module.prop` file.
|
||||
This will update the main [`Cargo.toml`](../Cargo.toml) file.
|
||||
|
||||
## Updating changelog links
|
||||
|
||||
@@ -19,14 +19,3 @@ Then, run the following command to generate the appropriate link references:
|
||||
```bash
|
||||
cargo xtask update-changelog
|
||||
```
|
||||
|
||||
## Build modules
|
||||
|
||||
To build avbroot's companion modules, run:
|
||||
|
||||
```bash
|
||||
cargo xtask modules -a
|
||||
# or -m <module1> -m <module2> ...
|
||||
```
|
||||
|
||||
See the main [`README.md`](../README.md#avbroot-magisk-modules) for more details.
|
||||
|
||||
+1
-4
@@ -4,13 +4,12 @@
|
||||
*/
|
||||
|
||||
mod changelog;
|
||||
mod module;
|
||||
mod version;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use crate::{module::ModulesCli, version::SetVersionCli};
|
||||
use crate::version::SetVersionCli;
|
||||
|
||||
const WORKSPACE_DIR: &str = env!("CARGO_WORKSPACE_DIR");
|
||||
|
||||
@@ -19,7 +18,6 @@ fn main() -> Result<()> {
|
||||
|
||||
match cli.command {
|
||||
Command::SetVersion(c) => version::set_version_subcommand(&c),
|
||||
Command::Modules(c) => module::modules_subcommand(&c),
|
||||
Command::UpdateChangelog => changelog::update_changelog_subcommand(),
|
||||
}
|
||||
}
|
||||
@@ -27,7 +25,6 @@ fn main() -> Result<()> {
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum Command {
|
||||
SetVersion(SetVersionCli),
|
||||
Modules(ModulesCli),
|
||||
/// Update links in CHANGELOG.md.
|
||||
UpdateChangelog,
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andrew Gunnerson
|
||||
* SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env,
|
||||
ffi::OsStr,
|
||||
fmt,
|
||||
fs::{self, File},
|
||||
io::{self, BufWriter, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use clap::{Args, Parser, ValueEnum};
|
||||
use tempfile::TempDir;
|
||||
use walkdir::WalkDir;
|
||||
use zip::{write::FileOptions, ZipWriter};
|
||||
|
||||
use crate::WORKSPACE_DIR;
|
||||
|
||||
#[cfg(unix)]
|
||||
const D8: &str = "d8";
|
||||
#[cfg(windows)]
|
||||
const D8: &str = "d8.bat";
|
||||
|
||||
fn newest_child_by_name(directory: &Path) -> Result<PathBuf> {
|
||||
let mut children = vec![];
|
||||
|
||||
for entry in fs::read_dir(directory)? {
|
||||
let entry = entry?;
|
||||
let path = entry
|
||||
.path()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|e| anyhow!("Non-UTF-8 path: {e:?}"))?;
|
||||
|
||||
children.push(path);
|
||||
}
|
||||
|
||||
children.sort_by(|a, b| human_sort::compare(a, b));
|
||||
|
||||
children
|
||||
.pop()
|
||||
.map(PathBuf::from)
|
||||
.ok_or_else(|| anyhow!("{directory:?} has no children"))
|
||||
}
|
||||
|
||||
fn build_dex(writer: &mut dyn Write, sources: &[&Path]) -> Result<()> {
|
||||
let sdk = env::var_os("ANDROID_HOME")
|
||||
.map(PathBuf::from)
|
||||
.ok_or_else(|| anyhow!("ANDROID_HOME must be set to the Android SDK path"))?;
|
||||
let build_tools = newest_child_by_name(&sdk.join("build-tools"))?;
|
||||
let platform = newest_child_by_name(&sdk.join("platforms"))?;
|
||||
let d8 = build_tools.join(D8);
|
||||
let android_jar = platform.join("android.jar");
|
||||
|
||||
let temp_dir = TempDir::new()?;
|
||||
|
||||
let mut process = Command::new("javac")
|
||||
.args(["-source", "1.8"])
|
||||
.args(["-target", "1.8"])
|
||||
.arg("-cp")
|
||||
.arg(android_jar)
|
||||
.arg("-d")
|
||||
.arg(temp_dir.path())
|
||||
.args(sources)
|
||||
.spawn()?;
|
||||
let status = process.wait()?;
|
||||
if !status.success() {
|
||||
bail!("javac failed with {status}");
|
||||
}
|
||||
|
||||
let mut class_files = vec![];
|
||||
|
||||
for entry in WalkDir::new(temp_dir.path()) {
|
||||
let entry = entry?;
|
||||
|
||||
if entry.path().extension() == Some(OsStr::new("class")) {
|
||||
class_files.push(entry.into_path());
|
||||
}
|
||||
}
|
||||
|
||||
let mut process = Command::new(d8)
|
||||
.arg("--output")
|
||||
.arg(temp_dir.path())
|
||||
.args(class_files)
|
||||
.spawn()?;
|
||||
let status = process.wait()?;
|
||||
if !status.success() {
|
||||
bail!("d8 failed with {status}");
|
||||
}
|
||||
|
||||
let mut reader = File::open(temp_dir.path().join("classes.dex"))?;
|
||||
io::copy(&mut reader, writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_props(data: &str) -> Result<HashMap<String, String>> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for line in data.split('\n') {
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some((k, v)) = line.split_once('=') else {
|
||||
bail!("Malformed line: {line:?}");
|
||||
};
|
||||
|
||||
result.insert(k.trim().to_owned(), v.trim().to_owned());
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn start_module(
|
||||
dist_dir: &Path,
|
||||
common_dir: &Path,
|
||||
module_dir: &Path,
|
||||
) -> Result<(PathBuf, ZipWriter<BufWriter<File>>)> {
|
||||
let module_prop_raw = fs::read_to_string(module_dir.join("module.prop"))?;
|
||||
let module_prop = parse_props(&module_prop_raw)?;
|
||||
|
||||
let name = module_prop["name"].as_str();
|
||||
let version = module_prop["version"].as_str();
|
||||
let version = version.strip_prefix('v').unwrap_or(version);
|
||||
let zip_path = dist_dir.join(format!("{name}-{version}.zip"));
|
||||
|
||||
let raw_writer = File::create(&zip_path)?;
|
||||
let mut zip_writer = ZipWriter::new(BufWriter::new(raw_writer));
|
||||
|
||||
zip_writer.start_file(
|
||||
"META-INF/com/google/android/update-binary",
|
||||
FileOptions::default(),
|
||||
)?;
|
||||
io::copy(
|
||||
&mut File::open(common_dir.join("update-binary"))?,
|
||||
&mut zip_writer,
|
||||
)?;
|
||||
|
||||
zip_writer.start_file(
|
||||
"META-INF/com/google/android/updater-script",
|
||||
FileOptions::default(),
|
||||
)?;
|
||||
io::copy(
|
||||
&mut File::open(common_dir.join("updater-script"))?,
|
||||
&mut zip_writer,
|
||||
)?;
|
||||
|
||||
zip_writer.start_file("module.prop", FileOptions::default())?;
|
||||
zip_writer.write_all(module_prop_raw.as_bytes())?;
|
||||
|
||||
Ok((zip_path, zip_writer))
|
||||
}
|
||||
|
||||
pub fn modules_subcommand(cli: &ModulesCli) -> Result<()> {
|
||||
let modules_dir = Path::new(WORKSPACE_DIR).join("modules");
|
||||
let common_dir = modules_dir.join("common");
|
||||
let dist_dir = modules_dir.join("dist");
|
||||
|
||||
fs::create_dir_all(&dist_dir)?;
|
||||
|
||||
let modules = if cli.module.all {
|
||||
Module::value_variants()
|
||||
} else {
|
||||
&cli.module.module
|
||||
};
|
||||
|
||||
for module in modules {
|
||||
let module_dir = modules_dir.join(module.to_string());
|
||||
|
||||
let (path, mut writer) = start_module(&dist_dir, &common_dir, &module_dir)?;
|
||||
|
||||
match module {
|
||||
Module::OemUnlockOnBoot => {
|
||||
writer.start_file("classes.dex", FileOptions::default())?;
|
||||
build_dex(&mut writer, &[&module_dir.join("Main.java")])?;
|
||||
|
||||
writer.start_file("service.sh", FileOptions::default())?;
|
||||
let mut reader = File::open(module_dir.join("service.sh"))?;
|
||||
io::copy(&mut reader, &mut writer)?;
|
||||
}
|
||||
}
|
||||
|
||||
writer.finish()?;
|
||||
|
||||
let path = path.canonicalize()?;
|
||||
println!("Built module: {path:?}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, ValueEnum)]
|
||||
#[value(rename_all = "lower")]
|
||||
enum Module {
|
||||
OemUnlockOnBoot,
|
||||
}
|
||||
|
||||
impl fmt::Display for Module {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.to_possible_value()
|
||||
.expect("no values are skipped")
|
||||
.get_name()
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[group(required = true, multiple = false)]
|
||||
pub struct ModuleGroup {
|
||||
/// Name of module.
|
||||
#[arg(short, long)]
|
||||
module: Vec<Module>,
|
||||
|
||||
/// Build all modules.
|
||||
#[arg(short, long, conflicts_with = "module")]
|
||||
all: bool,
|
||||
}
|
||||
|
||||
/// Build companion modules.
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct ModulesCli {
|
||||
#[command(flatten)]
|
||||
module: ModuleGroup,
|
||||
}
|
||||
+1
-52
@@ -27,43 +27,6 @@ fn update_cargo_version(version: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_module_version(path: &Path, version: &str) -> Result<()> {
|
||||
let mut version_code = 0;
|
||||
|
||||
// 8 bits per version component.
|
||||
for piece in version.split('.') {
|
||||
let piece: u32 = piece.parse()?;
|
||||
version_code <<= 8;
|
||||
version_code |= piece;
|
||||
}
|
||||
|
||||
let raw_reader = File::open(path)?;
|
||||
let mut reader = BufReader::new(raw_reader);
|
||||
let mut result = String::new();
|
||||
let mut line = String::new();
|
||||
|
||||
loop {
|
||||
line.clear();
|
||||
|
||||
let n = reader.read_line(&mut line)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if line.starts_with("version=") {
|
||||
result.push_str(&format!("version=v{version}\n"));
|
||||
} else if line.starts_with("versionCode=") {
|
||||
result.push_str(&format!("versionCode={version_code}\n"));
|
||||
} else {
|
||||
result.push_str(&line);
|
||||
}
|
||||
}
|
||||
|
||||
fs::write(path, &result)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_changelog_version(version: &str) -> Result<()> {
|
||||
let path = Path::new(WORKSPACE_DIR).join("CHANGELOG.md");
|
||||
let raw_reader = File::open(&path)?;
|
||||
@@ -109,26 +72,12 @@ fn update_changelog_version(version: &str) -> Result<()> {
|
||||
|
||||
pub fn set_version_subcommand(cli: &SetVersionCli) -> Result<()> {
|
||||
update_cargo_version(&cli.version)?;
|
||||
|
||||
let modules_dir = Path::new(WORKSPACE_DIR).join("modules");
|
||||
|
||||
for entry in fs::read_dir(modules_dir)? {
|
||||
let entry = entry?;
|
||||
|
||||
if entry.file_type()?.is_dir() {
|
||||
let module_prop = entry.path().join("module.prop");
|
||||
if module_prop.exists() {
|
||||
update_module_version(&module_prop, &cli.version)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_changelog_version(&cli.version)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the version number in all Cargo.toml files and in the module metadata.
|
||||
/// Set the version number in all Cargo.toml files.
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct SetVersionCli {
|
||||
/// Version number.
|
||||
|
||||
Reference in New Issue
Block a user