Android 7: NullPointerException при установке APK с помощью Runtime.getRuntime().exec

Я пытаюсь установить APK на Android 7 (Samsung и Sony), используя обычную процедуру Runtime.getRuntime.exec(). Установка завершается со следующим исключением в logcat:

09-04 14:14:33.932 16623-16623/? D/AndroidRuntime: Calling main entry com.android.commands.pm.Pm
09-04 14:14:33.939 3695-3876/? D/PackageInstaller:  installation of android.content.pm.PackageInstaller$SessionParams@a4d2f0e for non-container user 0
09-04 14:14:33.940 16623-16623/? E/Pm: Error
                                       java.lang.NullPointerException
                                           at android.os.Parcel.readException(Parcel.java:1699)
                                           at android.os.Parcel.readException(Parcel.java:1646)
                                           at android.content.pm.IPackageInstaller$Stub$Proxy.createSession(IPackageInstaller.java:249)
                                           at com.android.commands.pm.Pm.doCreateSession(Pm.java:530)
                                           at com.android.commands.pm.Pm.runInstall(Pm.java:369)
                                           at com.android.commands.pm.Pm.run(Pm.java:142)
                                           at com.android.commands.pm.Pm.main(Pm.java:99)
                                           at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
                                           at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:301)
09-04 14:14:33.941 16623-16623/? I/art: System.exit called, status: 1
09-04 14:14:33.941 16623-16623/? I/AndroidRuntime: VM exiting with result code 1

Я пытаюсь реализовать это так:

Process proc = Runtime.getRuntime().exec("pm install /sdcard/imo.apk");

так что:

Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/sh","-c","/system/bin/pm install /sdcard/imo.apk"});

Но исключение происходит в обоих случаях.

В андроидах меньше 7 работает.

Разрешения:

declared permissions:
  android.permission.INTERACT_ACROSS_USERS_FULL: prot=normal
requested permissions:
  android.permission.BIND_NOTIFICATION_LISTENER_SERVICE
  android.permission.READ_EXTERNAL_STORAGE
  android.permission.WRITE_EXTERNAL_STORAGE
  android.permission.READ_LOGS
User 0: ceDataInode=393939 installed=true hidden=false suspended=false stopped=false notLaunched=false enabled=0
  gids=[1007]
  runtime permissions:
    android.permission.CLEAR_APP_USER_DATA: granted=true
    android.permission.INSTALL_PACKAGES: granted=true
    android.permission.READ_EXTERNAL_STORAGE: granted=true
    android.permission.INTERACT_ACROSS_USERS_FULL: granted=true
    android.permission.READ_LOGS: granted=true
    android.permission.CLEAR_APP_CACHE: granted=true
    android.permission.WRITE_EXTERNAL_STORAGE: granted=true

Установка проходит через оболочку. заранее спасибо


person Jonah Tornovsky    schedule 04.09.2017    source источник
comment
Почему бы не использовать ACTION_INSTALL_PACKAGE?   -  person CommonsWare    schedule 04.09.2017
comment
НЕ ИСПОЛЬЗУЙТЕ Runtime.getRuntime.exec(). Вместо этого используйте ProcessBuilder. По крайней мере, это позволит вам изолировать ваш NPE.   -  person fge    schedule 04.09.2017
comment
Я также столкнулся с той же проблемой, пожалуйста, напишите ответ, если вы получили Спасибо.   -  person Rishikesh pathak    schedule 08.12.2017
comment
Привет, Rishikesh pathak, Исключение Null Pointer, вызванное причиной, которая начала появляться с Android 7. Пользователь PM, который устанавливает APK из вашего приложения (не из обычной оболочки), не имеет разрешения на это. Это должно быть ошибкой, но я действительно не знаю, собирается ли Google это исправить. В своем проекте я оставил проблему как предостережение.   -  person Jonah Tornovsky    schedule 11.12.2017
comment
Спасибо @JonahTornovsky за быстрый ответ, но я пытаюсь установить приложение из сценария оболочки и получаю то же исключение, что и ваше. Пожалуйста, проверьте его для более подробной информации: stackoverflow.com/questions/47668812/   -  person Rishikesh pathak    schedule 11.12.2017
comment
Привет @Rishikeshpathak. Вы устанавливаете приложение по сценарию, который выполняется другим приложением, а не из оболочки. Это выглядит так же, как выполнить установку из вашего приложения. Вы можете использовать команду идентификатора оболочки Android, чтобы увидеть, какой пользователь выполняет вашу установку, просто поместите ее в свой скрипт и запустите свое приложение: id после того, как вы увидите, что такое идентификатор пользователя, используйте оболочку, чтобы переключиться на нее, и попробуйте выполнить вашу установку: $ YOUR_ROOT USER_ID $ pm install -r /sdcard/Download/SampleApplication.apk; и увидеть результат. Вероятно, вы получите что-то вроде этого: Ошибка: java.lang.NullPointerException   -  person Jonah Tornovsky    schedule 12.12.2017
comment
Интересно, вы нашли решение? то же самое. Я только что обновился с M до N, а затем мой код просто перестает работать с этим NullPointerException.   -  person York Yang    schedule 13.05.2018


Ответы (2)


Я нашел ответ. Хотя я не уверен, какова точная причина, но это работает. Я ссылался на этот блог https://shoewann0402.github.io/2017/06/27/android-n-installSilent-and-uninstallSilent/, но это все китайское. В случае, если вы также понимаете китайский язык или используете перевод Google.

Новая команда должна быть такой:

pm install -i <you installer package name> --user 0 /sdcard/com.ifeng.news2.apk

Это какой-то новый механизм безопасности, добавленный Google, и он требует установки с использованием идентификатора пользователя 0. Также вам необходимо указать имя пакета установщика.

Затем в файле манифеста приложения-установщика добавьте android.permission.INTERACT_ACROSS_USERS_FULL это разрешение. Тогда это должно работать. Я видел, что есть некоторые документы о userId, но просто не хватает времени, чтобы копаться в них. Если вам интересно, вы можете поискать самостоятельно.

person York Yang    schedule 14.05.2018
comment
Спасибо работает как шарм! - person Arsenius; 11.03.2021

У меня была такая же проблема, но я решил ее по-другому. Мое приложение является пусковой установкой и имеет системные привилегии. Это мое решение.

Добавить в заголовок манифеста android:sharedUserId="android.uid.system"

Добавьте это разрешение в mainifest android:name="android.permission.INSTALL_PACKAGES".

Добавьте этот код в фоновый поток


    try {
        String cmd = "pm install -r -i " + LAUNCHER_PACKAGE_ID + " " + activity.getFileStreamPath(apkPath);
        Process p = Runtime.getRuntime().exec(cmd);
        p.waitFor();
    } 
    catch (Exception e) {
        Log.d(TAG, "SilentInstallActivity error: " + e);
    }

Подпишите приложение для Android с помощью системного ключа.

person Pavel Bobkov    schedule 23.06.2018
comment
Спасибо работает как шарм! - person Arsenius; 11.03.2021