[android] 부여 된 INSTALL_PACKAGES 권한을 사용하여 자동으로 앱 설치

시스템에 apk를 자동으로 설치하려고합니다. 내 앱은 / system / app에 있으며 “android.permission.INSTALL_PACKAGES”권한이 성공적으로 부여되었습니다.

그러나이 권한을 사용하는 방법을 어디서도 찾을 수 없습니다. / data / app에 파일을 복사하려고했지만 성공하지 못했습니다. 또한이 코드를 사용해 보았습니다.

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(
            Uri.parse("file:///sdcard/app.apk"),
            "application/vnd.android.package-archive");
    startActivity(intent);

그러나이 코드는 표준 설치 대화 상자를 엽니 다. 권한이 부여 된 루트없이 자동으로 앱을 설치하려면 어떻게해야 android.permission.INSTALL_PACKAGES합니까?

추신 : 처음 시작할 때 폴더에서 시스템으로 많은 APK를 설치하는 앱을 작성 중입니다 (설치 마법사 교체). 펌웨어를 가볍게 만들기 위해 필요합니다.

내가 바이러스를 작성하고 있다고 생각하는 경우 : 모든 프로그램이 / data / app에 설치됩니다. 권한 Install_packages는 / system / app에 있거나 시스템 키로 서명 된 시스템 수준 프로그램에만 부여 할 수 있습니다. 그래서 바이러스는 거기에 도달 할 수 없습니다.

로 말했다 http://www.mail-archive.com/android-porting@googlegroups.com/msg06281.html 애플리케이션들이 install_packages 권한이있는 경우 설치 침묵 할 수 있습니다. 또한 패키지를 자동으로 설치하기 위해 Install_packages 권한이 필요하지 않습니다. 또한 http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html



답변

첫 번째 방법은 Android의 기본 PackageInstaller 를 살펴 보는 것 입니다. 원하는 방식으로 해당 앱을 수정하거나 필요한 기능을 추출하는 것이 좋습니다.


특히 PackageInstallerActivity 와 그 방법 을 살펴보면 다음 과 onClickListener같습니다.

 public void onClick(View v) {
    if(v == mOk) {
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        ...
        newIntent.setClass(this, InstallAppProgress.class);
        ...
        startActivity(newIntent);
        finish();
    } else if(v == mCancel) {
        // Cancel and finish
        finish();
    }
}

그러면 실제 설치 프로그램이 InstallAppProgress 클래스에 있음을 알 수 있습니다. 그 클래스를 살펴보면 이것이 initView핵심 설치 프로그램 함수라는 것을 알 수 있으며 마지막으로하는 일은 PackageManagerinstallPackage함수를 호출하는 것입니다.

public void initView() {
...
pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
}

다음 단계는 추상 클래스 인 PackageManager 를 검사 하는 것입니다. installPackage(...)거기에서 기능을 찾을 수 있습니다. 나쁜 소식은 @hide로 표시되어 있다는 것입니다. 이것은 직접 사용할 수 없음을 의미합니다 (이 메서드를 호출하여 컴파일 할 수 없음).

 /**
  * @hide
  * ....
  */
  public abstract void installPackage(Uri packageURI,
             IPackageInstallObserver observer,
             int flags,String installerPackageName);

그러나 리플렉션을 통해이 메서드에 액세스 할 수 있습니다.

PackageManagerinstallPackage기능이 어떻게 구현 되는지에 관심이 있다면 PackageManagerService를 살펴보십시오 .

요약

를 통해 패키지 관리자 개체를 Context가져와야 getPackageManager()합니다. 그런 다음 installPackage리플렉션을 통해 함수를 호출 합니다.


답변

ADB가 앱을 설치하는 방법을 확인했습니다.
-APK
를 / data / local / tmp에 복사합니다
.- ‘shell : pm install /data/local/tmp/app.apk’를 실행합니다.

나는 다음을 수행 하여이 동작을 복제하려고 시도했습니다. (PC에서 USB 케이블 사용)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
이것은 작동합니다. 앱이 설치되었습니다.

다른 앱을 설치해야하는 애플리케이션 (AppInstall)을 만들었습니다.
(비 뿌리 장치, 일반적으로 설치)
이 수행합니다
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
그러나 이것은 오류가 있습니다 :
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
오류가없는 AppInstall에 의해, 오후에 의해 발생되는 것 같다.
SecurityException은 AppInstall에 의해 포착되지 않고 앱이 충돌하지 않기 때문입니다.

루팅 된 기기 (동일한 앱과 AppInstall)에서 똑같은 작업을 시도했는데 매력처럼 작동했습니다.
(또한 일반적으로 / system 또는 다른 곳에 설치되지 않음)
AppInstall은 루트 권한을 요청하지 않았습니다.
그러나 셸은 항상 해당 장치 #대신에 있기 때문 $입니다.

Btw, / system에 앱을 설치하려면 루트가 필요합니다. 맞습니까?
나는 루팅되지 않은 장치에서 adb remount를 시도하고 얻었습니다.
remount failed: Operation not permitted.
그래서 루팅되지 않은 장치 에서 / system 일을 시도 할 수 없었습니다.

결론 : 루팅 된 기기를 사용해야합니다.
도움이되기를 바랍니다. 🙂


답변

최근 사용자 동의없이 설치를 구현하고 있습니다. API 레벨 21 이상을위한 키오스크 애플리케이션으로 환경을 완전히 제어 할 수있었습니다.

기본 요구 사항은 다음과 같습니다.

  • API 레벨 21 이상
  • 시스템 권한이있는 앱으로 업데이터를 설치하기위한 루트 액세스 .

다음 메소드는 InputStream에서 APK를 읽고 설치합니다.

public static boolean installPackage(Context context, InputStream in, String packageName)
            throws IOException {
        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        params.setAppPackageName(packageName);
        // set params
        int sessionId = packageInstaller.createSession(params);
        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
        OutputStream out = session.openWrite("COSU", 0, -1);
        byte[] buffer = new byte[65536];
        int c;
        while ((c = in.read(buffer)) != -1) {
            out.write(buffer, 0, c);
        }
        session.fsync(out);
        in.close();
        out.close();

        Intent intent = new Intent(context, MainActivity.class);
        intent.putExtra("info", "somedata");  // for extra data if needed..

        Random generator = new Random();

        PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT);
            session.commit(i.getIntentSender());


        return true;
    }

다음 코드는 설치를 호출합니다.

 try {
     InputStream is = getResources().openRawResource(R.raw.someapk_source);
                    installPackage(MainActivity.this, is, "com.example.apk");
     } catch (IOException e) {
                    Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
     }

모든 것이 작동하려면 INSTALL_PACKAGES권한 이 절실히 필요합니다 . 그렇지 않으면 위 코드가 조용히 실패합니다.

<uses-permission
        android:name="android.permission.INSTALL_PACKAGES" />

이 권한을 얻으려면 루트가 필요한 시스템 애플리케이션으로 APK를 설치해야합니다 (업데이터 애플리케이션을 설치 한 후에는 루트없이 작동하는 것 같습니다).

시스템 애플리케이션으로 설치하기 위해 서명 된 APK를 생성하고

adb push updater.apk /sdcard/updater.apk

다음으로 이동 system/priv-app-FS를 다시 마운트해야 함 (이것이 루트가 필요한 이유입니다)

adb shell
su
mount -o rw,remount /system
mv /sdcard/updater.apk /system/priv-app
chmod 644 /system/priv-app/updater.apk

어떤 이유로 간단한 디버그 버전에서는 작동하지 않았지만 어떤 이유로 애플리케이션 이 선택되지 않으면 logcat 에 유용한 정보가 표시됩니다 priv-app.


답변

정의해야합니다

<uses-permission
    android:name="android.permission.INSTALL_PACKAGES" />

매니페스트에서 시스템 파티션 (/ system / app)에 있거나 제조업체에서 서명 한 애플리케이션이 있는지 여부에 관계없이 INSTALL_PACKAGES 권한을 갖게됩니다.

내 제안은 리플렉션을 통해 installPackages를 호출하고 패키지를 설치하고 실제 메서드를 호출하는 방법으로 jar를 내보내는 데 사용되는 1.5 호환성 수준의 작은 Android 프로젝트를 만드는 것입니다. 그런 다음 프로젝트에서 jar를 가져 오면 패키지를 설치할 준비가 된 것입니다.


답변

나는 루팅 된 Android 4.2.2에서 시도 했으며이 방법은 나를 위해 작동합니다.

private void installApk(String filename) {
    File file = new File(filename);
    if(file.exists()){
        try {
            final String command = "pm install -r " + file.getAbsolutePath();
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
}


답변

그 시간에 아무도 대답하지 않았기 때문에 어떻게해야할지 몰랐고이 허가에 대한 문서를 찾지 못했습니다. 그래서 나만의 해결책을 찾았습니다. 당신의 것보다 더 나쁘지만 어쨌든 이것은 해결책입니다.

/ data / app에 777 권한을 설정 한 busybox를 설치했습니다 (보안에 대해서는 신경 쓰지 않습니다). 그런 다음 앱에서 “busybox 설치”를 실행했습니다. 이것은 작동하지만 큰 보안 누출이 있습니다. 권한 777을 설정하면 루트가 필요하지 않습니다.


답변

android.content.pm.IPackageInstallObserver리플렉션으로 숨겨진 API 를 사용할 수 있습니다 .

public class PackageManagement {
    public static final int INSTALL_REPLACE_EXISTING = 0x00000002;
    public static final int INSTALL_SUCCEEDED = 1;

    private static Method installPackageMethod;
    private static Method deletePackageMethod;

    static {
        try {
            installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) {
        try {
            installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

android.content.pm.IPackageInstallObserver프로젝트로 가져 옵니다. 앱은 시스템이어야합니다. android.permission.INSTALL_PACKAGES매니페스트 파일에서 권한 을 활성화해야 합니다.