13

In Android 4.x, it was enough to put an APK-file into /system/priv-app, and the package-manager recognized that new file and (un-)installed the corresponding application or service.

Since Android L, it seems to be not enough to just put the file into that directory - a reboot of the system is required to force Android to recognize that change.

Has anyone an idea how to circumvent this? Maybe with any setprop ctl.restart xxx or by killing a dedicated service?

EDIT:

Here are some logs from logcat:

1. Move APK from /system to /system/priv-app (=installation)

su
mount -o remount rw /system
cd /system/priv-app
mv ../AARSCService.apk . // move from /system to /system/priv-app

W/mv      ( 3268): type=1400 audit(0.0:53): avc: denied { rename } for name="AARSCService.apk" dev="mmcblk0p22" ino=23041 scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0 tclass=file

(but file HAS been moved as the current root-implementation for Nexus 7 Android Android L P2 disables SELinux for the root-commands!)

-> APK NOT loaded and not listed in app-list -> NOT as expected, APK is going to be automatically installed once put into priv-app folder on Android 4.4.

2. Reboot device, having APK inside /system/priv-app

reboot

I/PackageManager(  567): /system/priv-app/AARSCService.apk changed; collecting certs

-> APK IS loaded and listed in app-list -> as expected

3. Move APK from /system/priv-app to /system (=deinstallation)

su
mount -o remount rw /system
cd /system/priv-app
mv AARSCService.apk .. // move from /system/priv-app to /system

W/mv      ( 3189): type=1400 audit(0.0:31): avc: denied { rename } for name="AARSCService.apk" dev="mmcblk0p22" ino=23041 scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0 tclass=file

(but file HAS been moved as the current root-implementation for Nexus 7 Android Android L P2 disables SELinux for the root-commands!)

-> APK still loaded and listed inside app-list, service inside app can still be bound from another app -> NOT as expected, APK is going to be automatically uninstalled once removed from priv-app folder on Android 4.4.

4. Reboot device, having APK NOT inside /system/priv-app

reboot 

W/PackageManager(  570): System package eu.airaudio.aarscservice no longer exists; wiping its data

-> APK is no more loaded and no more listed in app-list -> as expected

EDIT 2:

There's the same behaviour on unrooted Android L (21) emulator - sure, without the SELinux-warning. But the APK is also just (un-)installed after reboot (=kill zygote).

Martin L.
  • 3,006
  • 6
  • 36
  • 60
  • Just an observation, maybe it helps: The code that observes the `priv-app` folder hasn't changed from [KK](http://androidxref.com/4.4.4_r1/xref/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java#1285) to [L](https://android.googlesource.com/platform/frameworks/base/+/master/services/java/com/android/server/pm/PackageManagerService.java#1470). – Phillip Oct 28 '14 at 13:08
  • Hi Phillip, yes that's right and drives me more confused. But I have recognized that an APK providing a service is not installed/uninstalled anymore by simply placing/removing it into the "/system/priv-app"-directory. But the APK gets installed after a reboot of the device. It does not only affect my current application, but also my competitor's once who's theoretically doing exactly the same. Mysterious - I'll try to attach the debugger at the PackageManagerService in the next days. – Martin L. Oct 28 '14 at 15:12
  • @MartinM. can you add the log messages from `PackageManagerService` – ashoke Oct 29 '14 at 22:17
  • Hey ashoke, I have added a full workflow for adding & removing the APK, thanks for your support :) – Martin L. Oct 30 '14 at 21:49

6 Answers6

6

Comparing the source code of PackageManagerService between KitKat and Lollipop you can see significant changes, and some that are obviously related to this change.

PackageManagerService.java on Lollipop

PackageManagerService.java on KitKat

The most significant change to the question topic is the removal of all references to AppDirObserver (a nested class of PackageManagerService) that was initialized to monitor all directories (the attached image shows a comparison of the relevant code where it was used. Right side shows KitKat code and left side shows Lollipop) enter image description here

Still haven't found a solution for this but might help someone figure it out.

Muzikant
  • 8,070
  • 5
  • 54
  • 88
  • You are somewhat right Muzikant, the commit on 23th July introduced this "issue": https://github.com/android/platform_frameworks_base/commit/84e71d1d61c53cd947becc7879e05947be681103 I always checked the sources of preview #2 (I hope) and there those observer where still available. Hope someone might find a solution for this issue. 1000 Thanks! – Martin L. Nov 19 '14 at 15:43
  • Looking at that commit comment it mentions a "cluster-style" install which refers to how apps are now placed in "system/app-priv" folder (Each app has a folder that includes the APK and art files). I guess that if you'll find where this is built, you'll have a solution for your question. – Muzikant Nov 19 '14 at 16:25
  • Hey Muzikant, yes, I already read about this new cluster-style. I'll accept that a dynamically moved app is no more automaticaly installed and will ask my users to reboot their device to trigger the installation. Your answer is not about the question "how to trigger", but you answered "why it's no more working" - I will check how to honor it with some credits :) – Martin L. Nov 19 '14 at 20:31
3

Based on your logcat messages, looks like the PackageManagerService is not even seeing the folder/file changes.

Here is one way to circumvent/trigger a rescan, simulate a a "boot completed" event with broadcast action:

    adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

This should trigger a rescan by the PackageManagerService

ashoke
  • 6,441
  • 2
  • 26
  • 25
  • I haven't found a listener for that event in the PackageManagerService, but ok who knows. I will try this later this day and somwhat hope it will work. You'll receive the bounty on success - thanks again and in advance for looking into this! – Martin L. Nov 04 '14 at 12:55
  • Sadly, this hint will crash the whole system causing a soft-reboot. Interestingly, the system seems to now recognize that the APK changed, eg. if I remove it it starts to send PACKAGE_REMOVED, PACKAGE_ADDED-events, but it seems to struggle. Either that's really a bug in the latest developer-preview, or... any further idea? I think we are on the right way. – Martin L. Nov 04 '14 at 20:25
  • @MartinM. you can [try other standard broadcast actions](http://developer.android.com/reference/android/content/Intent.html), may be the `ACTION_PACKAGE_CHANGED` may help. – ashoke Nov 04 '14 at 20:34
  • Sadly not, seems to not trigger any re-scan, but just the default logs like "bla bla package xy changed". Even renaming the priv-app folder via mv and then renaming it back, doesn't trigger any event in the logs. I think & hope it's a bug in the latest preview.. that the rescan is working after a soft-crash of the system, is an indice that it should theoretically work :( – Martin L. Nov 04 '14 at 21:04
  • @MartinM. Looks like file/dir trigger [events can be either move or close_write](http://androidxref.com/4.4.4_r1/xref/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java#ADD_EVENTS). May be `cd` to `priv-app` folder, and try `touch tmp.txt;echo "0" >> tmp.txt`, see if triggers atleast `CLOSE_WRITE` (as the MOVED_TO event seems not working). – ashoke Nov 04 '14 at 22:29
  • Hey ashoke, good guess! But sadly no, even if I change the .txt to .apk and do a chmod 777 on it, no refresh is triggered. I was wrong with my previous statement that a soft-reboot will help - seemed to be an "accident" that it was partly working after some process-crashes caused by the BOOT_COMPLETED. I'm doing "reboot" between my tests, for sure :) – Martin L. Nov 04 '14 at 23:55
  • I have now created the same FileObserver as in PackageManagerService and can confirm, that this isn's working anymore. The same test ran as expected on an Android 4.4, but no event was triggered on Android 5p2. For me a clear indice that something in FileObserver is broken or maybe at the underlying inotify. Hope it's solved in the final version. – Martin L. Nov 05 '14 at 22:14
1

pms will scan /system/app(priv-app) at start. so just kill process systemserver :) it work at my lollipop emulator. just take a little while to showing "upgrade android, opt app..."

Robert
  • 5,278
  • 43
  • 65
  • 115
bowdom
  • 11
  • 1
  • Hey Bowdom, thanks for the answer. That's theoretically fully correct, but not a user-friendly way. I prefer asking the user kindly to reboot manually and offering him to reboot his device manually via "reboot"-command :) – Martin L. Jan 08 '15 at 12:40
0
  1. Push apk to /system/priv-app/
  2. Run command: adb shell > su > am restart (using this command you don't loose adb connection)
  3. Wait for system boots - install script can wait for clean output of command: "adb shell dumpsys phone"

Snippet:

def am_restart(self):
    """Restarts am waits for complete Android boot."""

    self._log.info('Restarting application manager!')

    ret, out, err = self.shell('am restart', require_root=True)
    if ret != 0:
        self.log_failure('am restart', ret, out, err)
        return False

    on_main_screen = False
    while not on_main_screen:
        sleep(2)
        ret, out, err = self.shell('dumpsys phone')
        if ret != 0:
            self.log_failure('dumpsys phone', ret, out, err)
            return False
        if not (out or err):
            on_main_screen = True
            self._log.info('Application manager successfully restarted!')

    return True
Łukasz Zdun
  • 283
  • 1
  • 3
  • 6
  • Hi Zelman, thanks for your post. As a reboot is mandatory, it's ok for me to simply ask the user to reboot and additionally let him reboot via a "reboot now"-button. But your script is a nice addon, maybe someone else can integrate it :) – Martin L. Mar 25 '15 at 20:35
0

I had the exact same problem. Turns out when I coped the package back to priv-app it was copied with different permission

Permissions of all packages in priv-app (and app) :

rwx-r-x-r-x

Permission of the package I copied back :

rwx--------

A simple chmod -R a+rw <path/to/package> solved the problem

EDIT: Make sure your /system/ is not readonly by issuing mount -o remount,rw /system/

Ramast
  • 7,157
  • 3
  • 32
  • 32
  • This is not working for me. The package is still not automatically installed. Maybe I am missing something here. Could you post your complete shell commands? – Dominik Schürmann May 10 '15 at 19:19
  • That is the complete shell command. Just replace with path to your package for example chmod -R 755 /system/apps/Bluetooth/ Before doing that make sure the /system directory is not readonly mount -orw,remount /system – Ramast May 12 '15 at 04:51
  • I mean the complete shell commands for installing the apk into the system partition. Obviously, you need to move it to the system partition somehow. As discussed in this thread it works for Pre-Lollipop but not for Lollipop. My shell commands are here: https://gitlab.com/fdroid/fdroidclient/commit/68238478b68064abec9a82dce8b84d4b2891e77d#8d8edab1f2306d3a9b99a3615847a428023372f6_0_84 On Lollipop a restart is required to rescan the priv-app dir for newly moved apks. – Dominik Schürmann May 17 '15 at 13:40
  • adb push [-p] . Just choose any temporary dir in your mobile that you can write on (maybe /mnt/extSdCard/ ) and push your package there then from inside the adb shell do "mv /mnt/extSdCard/mypackage /system/priv-app" Hope that helps – Ramast May 19 '15 at 01:36
0

Here you go:

adb shell cmd package compile -f -r first-boot com.yourpackage.name
Zoli_K
  • 916
  • 7
  • 7