INSTALL_PACKAGES権限を付与して、アプリをサイレントインストールします


86

システムに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);

ただし、このコードは標準のインストールダイアログを開きます。許可を得てrootなしでアプリをサイレントインストールするにはどうすればよいandroid.permission.INSTALL_PACKAGESですか?

PS私は最初の起動時にフォルダからシステムに多くの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


9
@Fosco彼が相手先ブランド供給のようなデバイスを作っているとしたら?
dascandy 2011年

41
@Fosco誰が気にしますか?dascandyが説明するような有効な質問です。人々がこのような質問に「あなたはそれをするべきではない」と答えるとき、それは一般的に非生産的です。そのような答えで私たちはどのような理解を得ていますか?
zachM 2014年

3
非生産的と言えば..あなたはこのパーティーザックに2年強遅れており、質問は当初とは大きく異なって見えます。
Fosco 2014年

2
@FoscoLOL。また、これが最新のAndroidOSでも機能していることを確認できます。
POMATu 2014年

1
@LarsH F-Droidアプリをインストールしました。サイレントにインストールするのではなく、Androidのパッケージマネージャーにプロンプ​​トを表示するだけです。
JoaquinIurchuk18年

回答:


60

最初の賭けは、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をご覧ください

概要

あなたは経由して、パッケージマネージャオブジェクトを取得する必要がありますContextgetPackageManager()。次にinstallPackage、リフレクションを介して関数を呼び出します。


2
助けて!この手法の結果は次のようになります。原因:java.lang.SecurityException:ユーザー10101も現在のプロセスにもandroid.permission.INSTALL_PACKAGESがありません。私のアプリにはその許可がありますが
gregm 2011年

13
アプリはその権限を要求しますが、Androidはサードパーティのアプリにその権限を付与しません。LogCat権限関連のログについては、を参照してください。
inazaruk 2011年

@inazaruk / system / appにインストールされたアプリは、install_pakagesを使用するための許可を自動的に取得することを読みましたが、この投稿で説明されいるように、機能しないようです。ヒントを教えていただけますか?
ゾーブ2011年

3
リフレクションを介してinstallPackageを呼び出すにはどうすればよいですか?実際にはメソッドを実行できませんmethod = aPackageManagerClass.getMethod( "installPackage"、new Class [] {Uri.class、IPackageInstallObserver.class、Integer.TYPE、String.class}); IPackageInstallObserverも非表示になっているので、誰かが私が嘆願するのを手伝ってくれますか?ここにリフレクションを行うための正しいコードを投稿してください。
シラゲ2013年

7
回答のすべてのリンクが無効になっています。
Mayur Gangurde 2017

13

ADBがアプリをインストールする方法を確認しました。
-APKを/ data / local / tmpにコピーします
-'shell:pm install / data / local / tmp / app.apk 'を実行します

私は次のようにしてこの動作を再現しようとしました:(PCではusb-cableを使用)
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ではなくpmによってスローされたようです。
SecurityExceptionがAppInstallによってキャッチされず、アプリがクラッシュしないためです。

ルート権限を取得されたデバイス(同じアプリとAppInstall)で同じことを試しましたが、それは魅力のように機能しました。
(これも通常インストールされており、/ systemなどに
はありません)AppInstallはroot権限を要求しませんでした。
しかし、それはシェルが常にそのデバイス上では#なく$存在するためです。

ところで、/ systemにアプリをインストールするにはrootが必要ですよね?
ルート権限を取得していないデバイスでadbremountを試したところ、次のようになりました。ルート権限を取得していないデバイスで
remount failed: Operation not permitted.
/ systemを試すことができなかったのはそのためです。

結論:ルート化されたデバイスを使用する必要があります
これが役立つことを願っています:)


これを機能させることができないようです。コマンドがADBシェルで正常に機能し、プログラムで実行しようとすると機能しないように見えるのは興味深いことです。
saulpower 2012年

はい、同じ問題があります-シェルで動作しますが、アプリから呼び出された場合は動作しませんsu
velis 2016年

スーパー管理者権限を取得するなど、Googleデバイスで作業する他の方法はありますか?
Ramesh Kumar

スーパー管理者権限が必要な場合は、1)デバイスをルート化する、2)アプリをシステムパーティションにインストールする、3)または、アプリをOS自体と同じキーで署名する必要があります。
FrankkieNL 2016

1
これは、ADBユーザーとアプリケーションのユーザーの権限が異なるために発生します
PHPoenX

11

最近、ユーザーの同意なしにインストールを実装しています。これは、環境を完全に制御できるAPIレベル21以降のキオスクアプリケーションでした。

基本的な要件は次のとおりです。

  • APIレベル21以上
  • アップデーターをシステム特権アプリとしてインストールするためのrootアクセス

次のメソッドは、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


「何らかの理由で、単純なデバッグバージョンでは機能しませんでした」リリースで機能したのですか、それとも他の「単純な」デバッグバージョンでは機能しなかったのですか?
JM卿

1
@JMLord署名付きリリースバージョンで動作し、署名付きデバッグバージョンと署名なしデバッグバージョンの両方で動作しませんでした-署名付きデバッグバージョンIで動作しなかったのは奇妙だと思いますが、調査する時間がありませんでした。それでも、APKがインストールされているかどうかを確認するには、システムlogcatログが非常に重要です。
Boris Treukhov 2017年

確かに、何らかの理由で、リリースとしてインストールすることがINSTALL_PACKAGES権限を取得するための鍵でした。アプリはpriv-appから署名付きデバッグで実行できましたが、アクセス許可リクエストは拒否されました。どうもありがとう!
JM卿

@BorisTreukhovねえ、packageNameパラメーターの目的について確認できますか?InputStreamをFileInputStreamに変更しましたが、次のエラーメッセージが表示されます:/data/app/vmdl676191029.tmp/COSUの解析に失敗しました

これらのコマンドの後にシステムprivアプリをインストールする方法は?
user2323471

8

定義する必要があります

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

マニフェストで、システムパーティション(/ system / app)にいる場合でも、アプリケーションが製造元によって署名されている場合でも、INSTALL_PACKAGESアクセス許可が必要になります。

私の提案は、リフレクションを介してinstallPackagesを呼び出すために使用される1.5互換性レベルの小さなAndroidプロジェクトを作成し、パッケージをインストールして実際のメソッドを呼び出すためのメソッドを含むjarをエクスポートすることです。次に、プロジェクトにjarをインポートすることで、パッケージをインストールする準備が整います。


5

私はroot化されたAndroid4.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();
        }
     }
}

2
質問は、rootなしで、システム「INSTALL_PACKAGES」権限を持つアプリのインストールに関するものでした。あなたの答えには「su」が含まれているので、rootが必要です。
POMATu 2014

この回答ありがとうございます!同じコードを使用していましたが、「pminstall-r」の代わりに「adbinstall-r」を使用していたため、機能しませんでした。あなたは私をここでたくさんの時間を節約してくれました!
Jeff.H 2017

@Vladmir私はあなたの助けが必要です。少し時間をいただけますか。私はuに非常に感謝します
twana eng

4

その時誰も答えなかったので、私はこれをどのように行うのか分かりませんでした、そして私はこの許可についての文書を見つけませんでした。だから私は自分の解決策を見つけました。あなたよりも悪いですが、これはとにかく解決策です。

/ data / appに777権限を設定するbusyboxをインストールしました(セキュリティは気にしません)。次に、アプリから「busyboxinstall」を実行しました。これは機能しますが、セキュリティリークが大きくなります。権限777を設定した場合、rootは必要ありません。


3
このようなコードを使用しましたか? Process install; install = Runtime.getRuntime().exec("/system/bin/busybox install " + myAPK.getAbsolutePath()); int iSuccess = install.waitFor();
誰か

4

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マニフェストファイルで権限をアクティブ化する必要があります。


このコードをLollipopとMarshamallowでテストしましたか?私にとっては素晴らしいアプローチのようで、それを使いたい
Farhad Faghihi 2016年

ICSからLollipopまでテストしました
Hermann Poilpre 2016年

見るべき行は「あなたのアプリはシステムでなければならない」です。これはロリポップなどで機能すると確信しています。アプリが「システム」である、つまりアプリにシステム権限(基本的にはルート)がある場合に限ります。ただし、その場合は、コマンドラインインストーラーを使用することもできます。
ラッシーキヌネン2017

1
installPackageメソッドをどのように呼び出しますか?つまり、たとえばIPackageInstallObserverを取得するにはどうすればよいですか?
phoebus 2018年

installFlagsの値は何ですか?
シバムクマール

3

adb installコマンドを使用するだけで、APKをサイレントにインストール/更新できます。サンプルコードは以下のとおりです

public static void InstallAPK(String filename){
    File file = new File(filename); 
    if(file.exists()){
        try {   
            String command;
            filename = StringUtil.insertEscape(filename);
            command = "adb install -r " + filename;
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
        e.printStackTrace();
        }
     }
  }

ここで、StringUtilsとはどういう意味ですか?解決できないエラーに直面していますか?
AndroidOptimist 2014

申し訳ありませんが、説明する必要があります。これは文字列のカスタムクラスであり、このメソッドはパスが正しいことを確認します。あなたはそれを無視することができます
ZeeShaN AbbAs 2014年

3
StringUtilクラスとは何ですか。StringUtil.insertEscape()メソッドを投稿できますか?その行にコメントすると、exec()の実行中に例外エラーが発生するためです。コマンド:[su、-c、adb install -r /storage/sdcard0/Android/data/com.install.fileよろしくお願いします
sandeepmaaram 2014

java.io.IOException:exec()の実行中にエラーが発生しました。コマンド:[su、-c、adb install -r /storage/emulated/0/download/SwipeAnimation.apk]作業ディレクトリ:null環境:null-エラーについて説明していただけますか?マニフェストに権限がある場合
Sandeep P

1
発根の問題が解決した後の@ZeeShaNAbbAs ..ありがとう
Sandeep P

1

前提条件:

先に正しく指摘したように、APKはシステムによって署名される必要があります。これを実現する1つの方法は、AOSPイメージを自分でビルドし、ビルドにソースコードを追加することです。

コード:

システムアプリとしてインストールしたら、パッケージマネージャーの方法を使用して、次のようにAPKをインストールおよびアンインストールできます。

インストール:

public boolean install(final String apkPath, final Context context) {
    Log.d(TAG, "Installing apk at " + apkPath);
    try {
        final Uri apkUri = Uri.fromFile(new File(apkPath));
        final String installerPackageName = "MyInstaller";
        context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

アンインストール:

public boolean uninstall(final String packageName, final Context context) {
    Log.d(TAG, "Uninstalling package " + packageName);
    try {
        context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

APKのインストール/アンインストール後にコールバックを行うには、次の方法を使用できます。

/**
 * Callback after a package was installed be it success or failure.
 */
private class InstallObserver implements IPackageInstallObserver {

    @Override
    public void packageInstalled(String packageName, int returnCode) throws RemoteException {

        if (packageName != null) {
            Log.d(TAG, "Successfully installed package " + packageName);
            callback.onAppInstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to install package.");
            callback.onAppInstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback after a package was deleted be it success or failure.
 */
private class DeleteObserver implements IPackageDeleteObserver {

    @Override
    public void packageDeleted(String packageName, int returnCode) throws RemoteException {
        if (packageName != null) {
            Log.d(TAG, "Successfully uninstalled package " + packageName);
            callback.onAppUninstalled(true, packageName);
        } else {
            Log.e(TAG, "Failed to uninstall package.");
            callback.onAppUninstalled(false, null);
        }
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

/**
 * Callback to give the flow back to the calling class.
 */
public interface InstallerCallback {
    void onAppInstalled(final boolean success, final String packageName);
    void onAppUninstalled(final boolean success, final String packageName);
}

===> Android 8.1でテストされ、正常に動作しました。


あなたの助けが必要です。少し時間をいただけますか。私はuに非常に感謝します
twana eng

私はあなたの助けが欲しいです。独自のAOSPを作成する方法を知る必要があります
twana eng

0

PackageManager.installPackageメソッドを使用して、サイレントインストール用のテストアプリを作成しました。

リフレクションを介してinstallPackageメソッドを取得し、srcフォルダーにandroid.content.pm.IPackageInstallObserverインターフェイスを作成しました(android.content.pmパッケージに隠されているため)。

installPackageを実行すると、文字列を示すSecurityExceptionが発生しました。これは、アプリにandroid.permission.INSTALL_PACKAGESがないことを示していますが、AndroidManifest.xmlで定義されています。

ですから、この方法は使えないと思います。

PS。Android SDK2.3および4.0でテストしました。多分それは以前のバージョンで動作します。


4.1と4.0、および2.1より前のAndroidバージョン(2.1を含む)で動作します。現在、4.0SDKを使用しています。/ system / appフォルダーに追加する必要があります。そうしないと、アプリにシステムレベル(rootではない)のアクセス許可が必要になりません。また、この方法でアプリをサイレントに削除できるので、削除に関する他の質問を確認してください。
POMATu 2013

はい、動作しますが、rootの権限のみが必要です。また、ルート化されていないデバイスのシステム/アプリにアプリをインストールすることはできません。
АндрейМосквичёв

ルートではなく、システムレベルの権限があります。ファームウェアのメーカーであれば、/ system / appに追加できます。私の場合-私はそうです(デバイスのメーカーにapkをファームウェアに追加するように依頼します)。他の方法でアプリをサイレントインストールすることはできません。そうしないと、セキュリティ上の大きな穴になります。
POMATu 2013

セキュリティホールについて-私はあなたに絶対に同意します。そして、この方法がどのアプリでも機能するのであれば、私にとっては驚きです。ルート権限を取得せずに/ system / appにアプリをインストールするにはどうすればよいですか?私はメーカーではありません。
АндрейМосквичёв

1
ルートまたは再フラッシュなしではできません。
POMATu 2013

0

LD_LIBRARY_PATH=/vendor/lib:/system/lib午後にインストールする前にこれを試してください。それはうまくいきます。


0

サードパーティのアプリケーションは、Androidアプリを適切にインストールできません。ただし、サードパーティのアプリケーションはAndroidOSにアプリケーションのインストールを要求できます。

したがって、これを定義する必要があります。

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

システムアプリとしてインストールして、アクセス許可を付与し、この定義を無視することもできます。(ルートが必要)

サードパーティのアプリで次のコマンドを実行して、ルート化されたデバイスにアプリをインストールできます。

コードは次のとおりです。

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();
    }
 }
}

この回答がお役に立てば幸いです。


0

Android6以降でサイレントインストールを実行することは可能です。Boris Treukhovの回答で提供されている関数を使用して、投稿内の他のすべてを無視します。rootも必要ありません。

アプリをデバイス管理者としてインストールします。バックグラウンドでアップデートをサイレントインストールするフルキオスクモードを使用できます。


0

私はすべての答えをチェックしました、結論はあなたがそれを機能させるために最初にデバイスへのルートアクセスを持っていなければならないということのようです。

しかし、私はこれらの記事が非常に役立つことに気づきました。私は「会社所有」のデバイスを作っているので。

ユーザーの操作なしでAndroidアプリをサイレントに更新する方法

Androidデバイスの所有者-最小限のアプリ

これが「マネージドデバイス」に関するグーグルのドキュメントです

フルマネージドデバイス



-6

!/ bin / bash

f=/home/cox/myapp.apk   #or $1 if input from terminal.

#backup env var
backup=$LD_LIBRARY_PATH
LD_LIBRARY_PATH=/vendor/lib:/system/lib
myTemp=/sdcard/temp.apk
adb push $f $myTemp
adb shell pm install -r $myTemp
#restore env var
LD_LIBRARY_PATH=$backup

これは私にとってはうまくいきます。私はこれをubuntu12.04のシェルターミナルで実行します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.