Archive

Posts Tagged ‘adb’

Android: Installing an Android App (APK) as a System App on the Android Emulator (v26) [Android 5.1+]

April 17, 2017 4 comments

I wanted to install a couple of APKs on the /system partition so that if I clear out the apps installed in the user partition, or I format/delete the user partition, i don’t lose my stuff.

NB: Installing to the /system partition also seems to have some extra benefits in terms of permissions, but I have not read into the details of what exactly happens. Also uninstalling via the GUI is not available (as far as i can see) once the app is installed on the /system partition

So the basic idea is that we want to get the given APK onto the /system partition and according to most tutorials and explanations i’ve found online it seems to be as easy as just copying the file onto the system partition and rebooting the device. But there are a few caveats that one needs to know. I’ll go through these below while also going through the steps that I used to eventually get my APK’s installed to the /system partition.

Common Steps across all methods:

You need to have the /system partition writable, this is done by first starting up the emulator with the -writable-system directive

emulator -avd -writable-system

The next step is to remount the AVD disks with the adb remount directive (I haven’t looked into what exactly happens here, but it seems to be needed, and works)


adb -e remount

After this, I noticed that there are 2 main methods, either copying the APK directly to the system partition, or installing the APK first to the user partition then “moving” it to the system partition.

The first method is useful for small APK files (i don’t have a specific definition of precisely what “small” means, but read on and you’ll get the idea); while the 2nd method is more appropriate for larger APKs. In general I noticed that larger APK files have other files in them and in the installation process the original APK gets split into a “base.apk” file, library dependencies (into a directory) and a couple of other “split files” derived from the APK. The best way to discover if this will happen to your APK is by using Method 2 (i.e. installing to the user partition, then “moving” the files to the system partition). The libraries and split files have an effect on the way things are installed on the system partition.

Method 1: Directly copying into the /system partition

The basic idea here is to just copy the given APK file either from your computer disk directly to the /system partition, or to copy it first to the SD Card (if available), or from some other writable location on your Android device (e.g. /usr/data/temp).

My suggestion is to create a folder in the /system/app/ directory with the package name of the APK. (it seems it is not entirely necessary, but for the sake of keeping the /system/app directory as clean as possible, i suggest this.)

This is done by going into the /system/app/ directory and using the mkdir command:


adb -e shell

cd /system/app

mkdir <PACKAGE_NAME>

The next step is to copy the APK from it’s original location into the /system/app directory. This can be done as follows:

If the APK is on your computer disk in some location:


adb -e push <APK_FILE_PATH> /system/app/<PACKAGE_NAME_DIR>/<APK_FILE_NAME>

E.g:

adb -e push C:\Users\user1\Desktop\myApp.apk /system/app/com.myPackage.package_name/myApp.apk

Since the directory is created as root it will likely have permissions set to 777 i.e. rwxrwxrwx . For security reasons it’s better to change these to something lower. I’m not exactly sure because some resources suggest 644 (i.e. r-xr–r–), while I think 755 is what is needed. All the same, change them:

chmod 755 /system/app/<PACKAGE_NAME_DIR>

If it copied successfully, you can reboot the device either with the Emulator Power button on the GUI, or using the adb -e reboot command

Method 2: Installing the APK to the User partition and then “moving” it to the System partition

Step 1: Similar to Method 1, for the sake of cleanliness, I suggest creating a folder in the /system/app partition. Use the mkdir command as described at the beginning of the instructions for Method 1. (Obviously,  before doing this, you should ensure that you started the emulator with the -writable-system directive, and used adb -e remount so that you can eventually have the /system partition as writable)

Step 2: Install the APK normally (from wherever it is, e.g on your computer, the SD Card etc) into the User partition of your device, using adb.


adb -e install <APK_FILE_PATH>

E.g: adb -e install C:\Users\user1\Desktop\myApp.apk

Step 3: Using adb get into the application installation directory and view how the APK was installed.


adb -e shell

cd /data/data/<APK_PACKAGE_NAME>

ls -al

E.g. adb -e /data/data/com.myPackage.package_name

In this directory you will probably see a couple of things including a /cache directory, a files directory, “split files” and a /lib directory (sym link) either to the /data/app-lib/ directory /vendor/lib/ or /system/lib/. You might also see /logs, /requests, /no_backup and /shared_prefs directories.

In my case i had a “base.apk” file, a /lib directory and lots of “split files” labelled split-lib-dependencies_apk.apk and split-lib-slice_0_apk.apk (numbered 0 to 9)

Step 4: Copy all the files from the installation directory in the User partition to the installation directory in the /system partition

In this step i opted to copy (using cp), rather than move (using mv) because mv was causing some unknown errors and i’ve read in some places something about problems with mv when trying to move directories across different partitions.

Since i was using cp i also elected to delete the directories and files in the user partition just after the copy was complete so as to mimic what i think should happen in a “move” operation.

Assuming you’re still in the installation directory in the User partition (from the previous step)

cp *.* /system/app/<APK_PACKAGE_NAME>/

E.g.:

cp *.* /system/app/com.myPackage.package_name/

If you want, you can check both the directories just to confirm that they look the same in terms of the copy being complete. In general if there were no errors, then the copy should have happened successfully.

cd /data/data/<APK_PACKAGE_NAME>/
ls -al
cd /system/app/<APK_PACKAGE_NAME>/

Since the directory in the system partition is created as root it will likely have permissions set to 777 i.e. rwxrwxrwx . For security reasons it’s better to change these to something lower. I’m not exactly sure to what exactly, because some resources suggest 644 (i.e. rw-r--r--), while I think 755 (i.e rwxr-xr-x)is what is needed. All the same, change them:

chmod 755 /system/app/<PACKAGE_NAME_DIR>

 

Note on Native Libraries:

If you have some native libraries built and deployed with your code (or in the APK that you’re trying to install as a system app), you will need to copy them either from within the APK file, by unzipping it’s contents, going into the /lib directory, into the folder that is named after the CPU architecture that your emulator or device is using (i.e. x86, x86-64, armeabi, etc); or from your compiled code (probably in <PROJECT_DIR>/app/build/intermediates/cmake/debug/obj if it’s a normal shared object library, or   <PROJECT_DIR>/app/src/main/assets/ if it is bundled as an ‘asset’) [*not sure if this asset part is actually true or necessary, but the *.so file for sure]

Alternatively if you had a /data/app-lib directory when you installed the APK in the user partition, you might find the library there.

The location you will probably have to copy the library to is either /system/lib/ or /vendor/lib/ (in some recent versions it is /system/vendor/lib ). You’ll notice in these directories the shared object library files (*.so) just sit there directly (no directory named according to the a package name)

You can copy from your device to the emulator using the adb -e push command

E.g:


adb -e push C:\Users\user1\Desktop\Unzipped_APK_Dir\lib\sharedlib.so /system/lib/sharedlib.so

or


adb -e shell

cp /data/app-lib/sharedlib.so /system/lib/sharedlib.so

or from wherever else, probably with cp

Once you are happy that all the copy events completed successfully, you can go to the APK installation in the user directory , list the contents of the APK installation directory in order to see the package that you want to remove and use that name when deleting the directory

cd /data/data/
ls -al
rm -r <APK_PACKAGE_NAME>

E.g.:

rm -r com.myPackage.package_name

Now you can reboot your device either with the adb -e reboot command, or through the Power Button, on the Emulator GUI.

On reboot your app should be installed. Try opening it. If it opens successfully (which was my case), then we’re all good. You can also try holding the App’s icon and if it is installed as a system app then you shouldn’t be able (as a normal user) to see the Remove/Uninstall dialog that usually appears at the top for other apps.

Extra Note: From the Android Platform Code documentation on Github [3]:

Parser for package files (APKs) on disk. This supports apps packaged either as a single “monolithic” APK, or apps packaged as a “cluster” of multiple APKs in a single directory.

Apps packaged as multiple APKs always consist of a single “base” APK (with a {@code null} split name) and zero or more “split” APKs (with unique split names). Any subset of those split APKs are a valid install, as long as the following constraints are met:

  • All APKs must have the exact same package name, version code, and signing certificates.
  • All APKs must have unique split names.
  • All installations must contain a single base APK.

 

References:

[1]. https://android.stackexchange.com/questions/27/how-do-i-properly-install-a-system-app-given-its-apk

[2]. https://www.isunshare.com/android/2-ways-to-convert-user-app-to-system-app.html

[3]. https://github.com/android/platform_frameworks_base/blob/master/core/java/android/content/pm/PackageParser.java

[4]. https://gist.github.com/chrislacy/3e09dda8e88a064d32fc634254fb4c9f

[5]. http://projectmaxs.org/documentation/systemapp.html

[6]. http://www.androidauthority.com/install-user-app-as-system-app-how-to-93522/

[7]. https://android.stackexchange.com/questions/3002/where-in-the-file-system-are-applications-installed/

[8]. https://developer.android.com/guide/topics/data/install-location.html

[9]. https://justus.berlin/2015/02/make-persistent-changes-to-system-in-android-emulator/

[10]. https://android.stackexchange.com/questions/150051/remounting-system-on-android-emulator-lasts-about-10-seconds-and-reverses-until

[11]. http://stackoverflow.com/questions/6066030/read-only-file-system-on-android

[12]. http://stackoverflow.com/questions/15417105/forcing-the-android-emulator-to-store-changes-to-system

 

 

Advertisements

Android Debug Bridge (adb): Useful commands – Notes

January 16, 2017 Leave a comment
  • Accessing an Android Device or Emulator […and getting Shell access]
 adb devices -l 
 adb -e 
 adb -e shell 

TThe -e directive initiates a connection to the Emulator, if there is only one emulator instance, otherwise it will throw an error

 adb -d 
 adb -d shell 

The -d directive initiates a connection to a Physical Android Device connected, if there is only one device connected, otherwise it will throw an error.

 adb -s <device_serial_identifier> 
 adb -s <device_serial_identifier> shell 

If there are multiple emulators, or multiple devices, or multiple of both connected, then the -s directive needs to be used to specify the specific “device/emulator” to connect to.

  • Installing and Uninstalling APKs
 adb -e install <APK_file_path> 
 adb -e uninstall <package_name> 
  • Errors when installing APKs:
    • INSTALL_FAILED_NO_MATCHING_ABIS
      • When the APK has native librariues that were built for a different architecture than what you are trying to run it on e.g. x86 and trying to run it on an ARM device, or built for ARM64 and trying to run it on ARM or x64; or ARM and trying to run it on x86 [1]
  • Getting ADB Root Permissions i.e. Root on the device
 adb root 
  • Listing packages (and file install locations)
 adb -e shell pm list packages -f 
 adb -d shell pm list packages -f 
  • Getting 3rd party packages only:
 adb shell pm list packages -f -3 

Sources:

[1] http://stackoverflow.com/questions/24572052/install-failed-no-matching-abis-when-install-apk

Categories: Android Tags: , , ,