Wednesday, April 26, 2017

stock android - Lollipop and above - How do I install an APK as a system app?


Back in the day, installing an app as a system app was as simple as moving the APK file to /system/app or /system/priv-app. Removing them was as simple as deleting the APK.


Now, while I'm customizing the phone's stock ROM, I've noticed that each and every app on the system partition was inside their own folder. I've tried to simply drop the APK in /system/app or /system/priv-app, but they don't work.


How do I install an app as a system app on Lollipop? I suspect something's up with SELinux and context, but I don't have root access. However, I have read/write access to the filesystem (by mounting the image in Linux).


UPDATE: I've tried Death Mask Salesman's suggestion and taken a look at logcat. The apps I want to pre-install (e.g. Instagram) are throwing this error:


01-01 01:04:45.108 5538-5538/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.instagram.android, PID: 5538
java.lang.RuntimeException: Unable to instantiate application com.instagram.app.InstagramAppShell: java.lang.ClassNotFoundException: Didn't find class "com.instagram.app.InstagramAppShell" on path: DexPathList[[zip file "/system/framework/com.google.android.maps.jar"],nativeLibraryDirectories=[/custpack/app/removeable/withlibs/com.instagram.android-1/lib/arm, /vendor/lib, /system/lib]]
at android.app.LoadedApk.makeApplication(LoadedApk.java:572)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4818)

at android.app.ActivityThread.access$1500(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1531)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5624)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.instagram.app.InstagramAppShell" on path: DexPathList[[zip file "/system/framework/com.google.android.maps.jar"],nativeLibraryDirectories=[/custpack/app/removeable/withlibs/com.instagram.android-1/lib/arm, /vendor/lib, /system/lib]]

at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at android.app.Instrumentation.newApplication(Instrumentation.java:985)
at android.app.LoadedApk.makeApplication(LoadedApk.java:567)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4818)
at android.app.ActivityThread.access$1500(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1531)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)

at android.app.ActivityThread.main(ActivityThread.java:5624)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
Suppressed: java.lang.ClassNotFoundException: com.instagram.app.InstagramAppShell
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)

... 13 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available



Symptoms:



  • All of the apps I've installed force closes

  • Their package names and the generic logo shows up on the launcher instead of their app name and logo

  • They simply don't work





To people planning to flag this as a duplicate, these answers don't work/are outdated/not applicable (not a live system/no root access):




Answer



Okay, I got it working. Here's how I did it:



  1. Copy the APK file to /system/app/some-folder/ or /system/priv-app/xyz-folder/.

    • Keeping them in their own folders may/will prevent conflicts. Some apps want to have their libs and other files extracted and placed alongside the APK in specific folders, although they're pretty rare.

    • Try checking out some folders of other system apps. Notice that some of them have a lib or other folder beside the APK.


    • That's why almost all of the apps in the folders mentioned above have their APKs inside their own folders.

    • Following step 1 is usually enough.



  2. Change the APK file's context using the command

    • chcon u:object_r:system_file:s0 /path/to/apk-file.apk

    • Or, if you copied it into its own folder, run chcon -R u:object_r:system_file:s0 /folder/where/the/APK/is/saved.





If the context isn't changed, Android won't treat your app as a system app. It will show up on the launcher as an app with a generic icon and zzz.package.name as the name.


In ye olde days (e.g. Gingerbread), you simply had to copy the APK in /system/app/ and set proper permissions. Times have changed.


No comments:

Post a Comment

samsung galaxy s 2 - Cannot restore Kies backup after firmware upgrade

I backed up my Samsung Galaxy S2 on Kies before updating to Ice Cream Sandwich. After the upgrade I tried to restore, but the restore fails ...