Android Edge Agent is an Android application to run EPI client.
This project uses the official Node.js codebase, built for Android systems (with various architectures) using Termux - an open source project that emulates a terminal and provides a Linux environment on Android.
Termux allows to build a variety of packages and generate working binaries for usages in Android applications.
Termux packages contains scripts and patches to build packages for the Termux Android application.
Termux provides a Docker container with a build environment which is the easiest and fastest way to start building packages. Inside the container we can find a file structure that mimics a real Android environment.
A video including the steps needed to setup the environment and build any Termux package, including build options details can be found here.
The packages can also be built on Windows environment by using WSL 2, but every step starting from cloning the termux-packages git project must be done on the WSL 2 terminal. The complete build flow was executed successfully on Windows WSL 2 using Debian image.
Install steps (running on WSL 2 if on Windows):
- Clone termux-packages git project:
git clone https://github.com/termux/termux-packages
- Navigate to
termux-packages/nodejs/build.sh
to check the Node.js version that will be built, by checking the values specified inside the TERMUX_PKG_VERSION variable (e.g. 18.7.0). This can be adjusted accordingly with the desired version that needs to be built. - Start the termux docker instance by executing the script
./termux-packages/scripts/run-docker.sh
from the previously cloned git project. This will start the Termux docker instance (considering that Docker is correctly installed on the machine, e.g. Docker Windows if running on Windows WSL 2). - After successfully executing the previous command, the bash interface is now switched inside the termux image. Any time access is required on the termux image instance the previous step needs to be executed (it will access the existing image instance if it already exists). Once inside the termux instance, make sure that the current working directory is
/home/builder/termux-packages
. - To generate the Node.js build, the ONE of the following needs to be executed, based on the desired Android architecture that Node.js needs to be built for:
./build-package.sh nodejs -a aarch64
./build-package.sh nodejs -a arm
./build-package.sh nodejs -a x86_64
./build-package.sh nodejs -a i686
aarch64 corresponds to arm64-v8a Android architecture (64-bit ARM architecture)
arm corresponds to armeabi-v7a Android architecture (32-bit ARM architecture)
x86_64 corresponds to x86_64 Android architecture (64-bit x86 architecture)
i686 corresponds to x86 Android architecture (32-bit x86 architecture)
Note: only one architecture needs to be executed at a time, since the output is generated at the same location (/data/data/com.termux/files/usr
) invariant of the specified architecture. Be aware that this location is available only from the termux image instance. Also be aware that the build process is very resource and time consuming (~45 minutes on Windows WSL 2 with Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz staying in 100% usages, without executing anything else).
- In order to copy anything from docker container to the local file system we need to run the following command in order to get the container id:
docker ps
Then we can copy the contents from the container to the local file system using:
docker cp <container-id>:<src-path> <local-dest-path>
e.g.: docker cp d0a0334f8971:/data/data/com.termux/files/usr D:\output
- The following generated files should be included (by overwriting the old ones) based on the specified architecture:
- bin/node: this represents the main .so file and should be copied inside the Android project at
app\libs\{ARCHITECTURE}\libnode.so
(the file needs to be renamed tolibnode
and have theso
extension!). - lib: this folder contains all the node dependencies and they also needs to be included inside the Android project in order for Node.js to run. The whole folder content needs to be copied to
app/src/main/assets/{ARCHITECTURE}
. Afterwards, the files having thea
extension (e.g. libcrypto.a) need to be removed since they are not of use for Android - they represent static build result object (a represents archive since it's an archived object file). Next step is to remove the symlinks keep only the and original associated files which needs be renamed asso
files; e.g. having symlinkslibicudata.so
andlibicudata.so.71
which ultimately points tolibicudata.so.71.1
, the symlinks should be deleted and the original filelibicudata.so.71.1
renamed tolibicudata.so
. But before deleting the symlinks this information should be recorded inside theapp/src/main/assets/symlinks.json
configuration file (in json format), since the original file names of the dependencies needs to be replicated on the Android application, when the application is first opened.
Considering the following output from termux built for the lib
folder root files:
libc++_shared.so
libcares.so
libcrypto.a
libcrypto.so
libcrypto.so.3
libicudata.a
libicudata.so
libicudata.so.71
libicudata.so.71.1
libicui18n.a
libicui18n.so
libicui18n.so.71
libicui18n.so.71.1
libicuio.a
libicuio.so
libicuio.so.71
libicuio.so.71.1
libicutest.a
libicutest.so
libicutest.so.71
libicutest.so.71.1
libicutu.a
libicutu.so
libicutu.so.71
libicutu.so.71.1
libicuuc.a
libicuuc.so
libicuuc.so.71
libicuuc.so.71.1
libssl.a
libssl.so
libssl.so.3
libutil.so
libz.a
libz.so
libz.so.1
libz.so.1.2.12
Will need to have the following files inside app/src/main/assets/{ARCHITECTURE}
:
libc++_shared.so
libcares.so
libcrypto.so
libicudata.so
libicui18n.so
libicuio.so
libicutest.so
libicutu.so
libicuuc.so
libssl.so
libutil.so
libz.so
And the associated app/src/main/assets/symlinks.json
configuration file:
[
{ "originalFile": "libcrypto.so", "symlinkName": "libcrypto.so.3" },
{ "originalFile": "libicudata.so", "symlinkName": "libicudata.so.71" },
{ "originalFile": "libicudata.so", "symlinkName": "libicudata.so.71.1" },
{ "originalFile": "libicui18n.so", "symlinkName": "libicui18n.so.71" },
{ "originalFile": "libicui18n.so", "symlinkName": "libicui18n.so.71.1" },
{ "originalFile": "libicuio.so", "symlinkName": "libicuio.so.71" },
{ "originalFile": "libicuio.so", "symlinkName": "libicuio.so.71.1" },
{ "originalFile": "libicutest.so", "symlinkName": "libicutest.so.71" },
{ "originalFile": "libicutest.so", "symlinkName": "libicutest.so.71.1" },
{ "originalFile": "libicutu.so", "symlinkName": "libicutu.so.71" },
{ "originalFile": "libicutu.so", "symlinkName": "libicutu.so.71.1" },
{ "originalFile": "libicuuc.so", "symlinkName": "libicuuc.so.71" },
{ "originalFile": "libicuuc.so", "symlinkName": "libicuuc.so.71.1" },
{ "originalFile": "libssl.so", "symlinkName": "libssl.so.3" },
{ "originalFile": "libz.so", "symlinkName": "libz.so.1" },
{ "originalFile": "libz.so", "symlinkName": "libz.so.1.2.12" }
]
At the time of writing the Node.js version is 18.7.0 and it was built for all four architectures.
This will basically install Node inside the Android application and make it run on a free port for the application to connect to.
Warning: Please be sure that you have at least 15GB free space on the device you want to make a build.
You must have JDK 11 installed. (Probably other versions of JDK - down to 8 - might work as we do not use specific JDK 11 features but we built it and test it using verison 11)
To see if you have java installed and what version run
java --version
You should get something like:
If you do not have JDK installed then follow this link - How to install JDK - to see how to install it on your machine.
Download version 4.1 from Download Android Studio page
Note: Please try to to stick with 4.1 of the Studio as any new version (slight increase in version number) might convert and upgrade the project file(s) which might trigger a chain reaction of upgrades that might put whole project into a configration that was not tested yet.
Menu > Tools > SDK Manager > SDK Tools > Show Package Details > NDK (Side by side) > 21.3.6528147
Note: SKIP THIS STEP if you are using this repository from inside the epi-workspace
Copy project inside app/src/main/assets/nodejs-project/ folder
cd app/src/main/assets/nodejs-project/
npm install
Menu > Tools > AVD Manager > + Create Virtual Device... > Phone > Pixel 4 > (Next) > Release Name (Pie) / API Level 28 > Next > AVD Name: Pixel 4 API 30 > (Finish)
Note: Set proper permissions for application: #App Info > Permissions > (3 dots) > All permissions
Create a folder named android (we will use ${android_home} to refer to it) and subfolders.
mkdir -p ~/${android_home}/sdk/cmdline-tools/latest/
This is based on the Android SDK, so you need to download it
Go to https://developer.android.com/studio#downloads and search for "SDK tools package" inside "Command line tools only" section.
Unzip the content of zip file into
${android_home}/sdk/cmdline-tools/latest/
Make sure you can run sdkmanager from
${android_home}/sdk/cmdline-tools/latest/bin/
folder.
Create a local file named local.properties and add
sdk.dir=~/${android__home}/sdk
replacing the right value with your path to SDK
Windows Run gradle.bat in Command Prompt
Linux Run gradlew in console.
Tip: If gradlew is not running make it executable with
chmod +x gradlew
./gradle(w) tasks
Inside project's folder type:
./gradlew -b ndk.gradle installNDK
For debug version run
./gradlew assembleDebug
For release version run
./gradlew assembleRelease
This will create an .apk file inside app/build/output/apk/debug
folder.
If beside building you want to run it on a device
./gradlew installDebug
This will install the application on the default (running) emulator but IT WILL NOT LAUNCH IT FOR YOU.
See this link
By default the release version of the APK is signed.
To make a release APK run
./gradlew assembleRelease
By default a keystore file (app/epi.jks) is used and a default credentials properties file (app/sign.settings). They are created by default.
To change the password keystore and access credentials to it you have to update those files.
You can debug the inner browser (WebView) by typing
chrome://inspect
inside your Chrome browser.
You will get something like
More information here: Remote Debugging WebViews