Skip to content

Commit

Permalink
Add support for local development with an emulator
Browse files Browse the repository at this point in the history
  • Loading branch information
stevesoltys committed Sep 10, 2023
1 parent 489474f commit 08a24ae
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 1 deletion.
68 changes: 68 additions & 0 deletions .idea/runConfigurations/app_emulator.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ It uses the same internal APIs as `adb backup` which is deprecated and thus need

## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/seedvault-app/seedvault.
See [DEVELOPMENT.md](app/development/DEVELOPMENT.md) for information on developing Seedvault locally.

This project aims to adhere to the [official Kotlin coding style](https://developer.android.com/kotlin/style-guide).

Expand Down
41 changes: 40 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ android {
// https://android.googlesource.com/platform/build/+/refs/tags/android-11.0.0_r29/target/product/security/platform.pk8
keyAlias "platform"
keyPassword "platform"
storeFile file("platform.jks")
storeFile file("development/platform.jks")
storePassword "platform"
}
}
Expand Down Expand Up @@ -171,3 +171,42 @@ configurations {
}
}
}

tasks.register('provisionEmulator', Exec) {
group("emulator")

dependsOn(tasks.assembleRelease)

doFirst {
commandLine "${project.projectDir}/development/scripts/provision_emulator.sh",
"seedvault",
"system-images;android-33;google_apis;x86_64"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}

tasks.register('startEmulator', Exec) {
group("emulator")

doFirst {
commandLine "${project.projectDir}/development/scripts/start_emulator.sh", "seedvault"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}

tasks.register('installEmulatorRelease', Exec) {
group("emulator")

dependsOn(tasks.assembleRelease)

doFirst {
commandLine "${project.projectDir}/development/scripts/install_app.sh"

environment "ANDROID_SDK_HOME", android.sdkDirectory.absolutePath
environment "JAVA_HOME", System.properties['java.home']
}
}
50 changes: 50 additions & 0 deletions app/development/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Development

## Using an emulator

It is possible to use an emulator to work on Seedvault. This is likely the path of least resistance, since you don't need to build AOSP from source to make and test code changes.

It's also helpful for quickly testing Seedvault on newer versions of Android.

### Setup

After opening the project in Android Studio, try running the `app:provisionEmulator` Gradle task.

This task runs the script in `scripts/provision-emulator.sh`:

```bash
./app/development/scripts/provision-emulator.sh "seedvault" "system-images;android-33;google_apis;x86_64"
```
Please note that this has only been tested on Linux.

### Starting the emulator

You should use the Gradle task `app:startEmulator` to develop with the emulator. This is to ensure
the `-writable-system` flag is set when the emulator starts (required to install Seedvault).

This task runs the script in `scripts/start-emulator.sh`:

```bash
./app/development/scripts/start-emulator.sh "seedvault"
```

### Testing changes

Once the emulator is provisioned and running, you should be able to use the `app:installEmulatorRelease`
Gradle task to install updates.

This task depends on `app:assembleRelease` and runs the script in `scripts/install_app.sh`:

```bash
./app/development/scripts/install_app.sh
```

There's also an Andriod Studio runtime configuration `app-emulator` which will build, install, and automatically launch the `com.stevesoltys.seedvault.settings.SettingsActivity` as if you clicked `Backup` in settings.

### Notes

The `MANAGE_DOCUMENTS` permission will not be granted unless you are using a base AOSP
image. Currently byd default we are using the `google-apis` version of the image, which does not provide the
permission because it is not signed with the test platform key.

The [generic AOSP images](https://developer.android.com/topic/generic-system-image/releases) are signed with the test platform key, but at the time of writing there is no AOSP emulator image for Android 13 in the default SDK manager repositories.
File renamed without changes.
32 changes: 32 additions & 0 deletions app/development/scripts/install_app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
exit 1
fi

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

EMULATOR_DEVICE_NAME=$($ANDROID_SDK_HOME/platform-tools/adb devices | grep emulator | cut -f1)

if [ -z "$EMULATOR_DEVICE_NAME" ]; then
echo "Emulator device name not found"
exit 1
fi

ADB="$ANDROID_SDK_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"

$ADB root
sleep 3 # wait for adb to restart
$ADB remount # remount /system as writable

echo "Installing Seedvault app..."
$ADB shell mkdir -p /system/priv-app/Seedvault
$ADB push $ROOT_PROJECT_DIR/app/release/app-release.apk /system/priv-app/Seedvault/Seedvault.apk

echo "Installing Seedvault permissions..."
$ADB push $ROOT_PROJECT_DIR/permissions_com.stevesoltys.seedvault.xml /system/etc/permissions/privapp-permissions-seedvault.xml
$ADB push $ROOT_PROJECT_DIR/allowlist_com.stevesoltys.seedvault.xml /system/etc/sysconfig/allowlist-seedvault.xml
71 changes: 71 additions & 0 deletions app/development/scripts/provision_emulator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
exit 1
fi

# assert 2 parameters are provided
if [ $# -ne 2 ]; then
echo "Usage: $0 <emulator_name> <system_image>"
exit 1
fi

EMULATOR_NAME=$1
SYSTEM_IMAGE=$2

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

echo "Downloading system image..."
$ANDROID_SDK_HOME/cmdline-tools/latest/bin/sdkmanager --install "$SYSTEM_IMAGE"

# create AVD if it doesn't exist
if $ANDROID_SDK_HOME/cmdline-tools/latest/bin/avdmanager list avd | grep -q "$EMULATOR_NAME"; then
echo "AVD already exists. Skipping creation."
else
echo "Creating AVD..."
echo 'no' | $ANDROID_SDK_HOME/cmdline-tools/latest/bin/avdmanager create avd -n "$EMULATOR_NAME" -k "$SYSTEM_IMAGE"
sleep 1
fi

echo "Starting emulator..."
$SCRIPT_DIR/start_emulator.sh "$EMULATOR_NAME"
sleep 3

# get emulator device name from ADB
EMULATOR_DEVICE_NAME=$($ANDROID_SDK_HOME/platform-tools/adb devices | grep emulator | cut -f1)

if [ -z "$EMULATOR_DEVICE_NAME" ]; then
echo "Emulator device name not found"
exit 1
fi

ADB="$ANDROID_SDK_HOME/platform-tools/adb -s $EMULATOR_DEVICE_NAME"

echo "Waiting for emulator to boot..."
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'

echo "Provisioning emulator for write access to '/system'..."
$ADB root
sleep 3 # wait for adb to restart
$ADB remount # remount /system as writable

echo "Rebooting emulator..."
$ADB reboot # need to reboot first time we remount
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'

echo "Provisioning emulator for Seedvault..."
$SCRIPT_DIR/install_app.sh

echo "Setting backup transport to Seedvault..."
$ADB shell bmgr enable true
$ADB shell bmgr transport com.stevesoltys.seedvault.transport.ConfigurableBackupTransport

echo "Rebooting emulator..."
$ADB reboot
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'

echo "Emulator '$EMULATOR_NAME' has been provisioned with Seedvault!"
22 changes: 22 additions & 0 deletions app/development/scripts/start_emulator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

# assert ANDROID_HOME is set
if [ -z "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME is not set"
exit 1
fi

# assert 1 parameter is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <emulator_name>"
exit 1
fi

EMULATOR_NAME=$1

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
DEVELOPMENT_DIR=$SCRIPT_DIR/..
ROOT_PROJECT_DIR=$SCRIPT_DIR/../../..

echo "Starting emulator..."
nohup $ANDROID_SDK_HOME/emulator/emulator -avd "$EMULATOR_NAME" -gpu swiftshader_indirect -writable-system -no-snapshot-load >/dev/null 2>&1 &

0 comments on commit 08a24ae

Please sign in to comment.