94

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

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

PS私は、最初の起動時にフォルダーからシステムに多くのapkをインストールするアプリを作成しています(セットアップウィザードを置き換えます)。ファームウェアを軽くするために必要です。

私がウイルスを書いていると思われる場合: すべてのプログラムは /data/app にインストールされます。パーミッション Install_packages は、/system/app にある、またはシステム キーで署名されたシステム レベルのプログラムにのみ付与できます。だからウイルスは入り込めない。

As said http://www.mail-archive.com/android-porting@googlegroups.com/msg06281.html apps CAN be silent installed if they have install_packages permission. Moreover you don't need Install_packages permission to install packages not silently. Plus http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html

4

17 に答える 17

62

最初の賭けは、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次に、リフレクションを介して関数を呼び出します。

于 2011-04-27T13:57:16.553 に答える
15

最近、ユーザーの同意なしにインストールを実装しています。これは、環境を完全に制御できる 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" />

この権限を取得するには、root が必要なシステム アプリケーションとして APK をインストールする必要があります(ただし、アップデータ アプリケーションをインストールした後は、root がなくても動作するようです)。

システム アプリケーションとしてインストールするには、署名済みの 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

于 2016-11-05T16:39:44.897 に答える
13

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ではなくpmによってエラーがスローされたようです。
SecurityException が AppInstall によってキャッチされず、アプリがクラッシュしないためです。

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

ところで、/system にアプリをインストールするには root が必要ですよね?
ルート化されていないデバイスで adb remount を
remount failed: Operation not permitted.
試してみたところ、次のようになりました。

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

于 2012-05-20T13:51:40.070 に答える
8

定義する必要があります

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

マニフェストで、システム パーティション (/system/app) にいるか、製造元によって署名されたアプリケーションを持っているかに関係なく、INSTALL_PACKAGES 権限が付与されます。

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

于 2012-02-13T11:21:35.453 に答える
5

ルート化された 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();
        }
     }
}
于 2014-02-20T09:44:08.850 に答える
4

その時は誰も答えなかったので、これを行う方法がわかりませんでした。また、この許可に関するドキュメントも見つかりませんでした。だから私は自分の解決策を見つけました。あなたのものよりも悪いですが、これはとにかく解決策です。

/data/app に 777 パーミッションを設定する busybox をインストールしました (セキュリティは気にしません)。次に、アプリから「busybox install」を実行しました。これは機能しますが、大きなセキュリティ リークがあります。アクセス許可を 777 に設定すると、root は必要ありません。

于 2011-07-19T11:25:26.113 に答える
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マニフェスト ファイルで権限を有効にする必要があります。

于 2014-11-27T13:21:35.027 に答える
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();
        }
     }
  }
于 2013-08-29T10:37:14.473 に答える
0

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

于 2014-02-04T05:10:59.417 に答える
0

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

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

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

したがって、この方法を使用することは不可能だと思います。

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

于 2013-02-13T18:48:58.527 に答える
0

答えで@inazarukが述べたように、installPackageメソッドは非表示であり、リフレクションによって呼び出す必要があります。ただし、パラメータとしてIPackageInstallObserver渡されるコールバックも隠されているinstallPackageため、このインターフェイスを実装するには動的プロキシを使用する必要があります。以下に、リフレクションとプロキシの両方を使用するコード スニペットを示します。

private void silentAppInstall(Uri apkUri){
        PackageManager pm = getContext().getPackageManager();
        try {
            Class<?> cPackageInstallObserver = Class.forName("android.content.pm.IPackageInstallObserver");
            Object installObserver = Proxy.newProxyInstance(cPackageInstallObserver.getClassLoader(),
                    new Class[]{cPackageInstallObserver}, new InstallObserverHandler());
            Class<?>[] types = new Class[] {Uri.class, cPackageInstallObserver, int.class, String.class};
            Method method = pm.getClass().getMethod("installPackage", types);
            method.invoke(pm, apkUri, installObserver, 2, null);
        } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
}

static class InstallObserverHandler implements InvocationHandler {

        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("packageInstalled")){
                // Place you code here
            }
            return null;
        }
}
于 2021-07-07T13:13:01.677 に答える
-6

!/ビン/バッシュ

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

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

于 2014-06-06T05:53:12.570 に答える