以授予的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
说到无用的..您参加本次聚会Zach的时间已经晚了2年多,这个问题看起来与最初的问题大相径庭。
Fosco 2014年

2
@Fosco哈哈。我也可以确认这仍在最新的Android OS中正常工作。
POMATu

1
@LarsH我刚刚安装了F-Droid应用程序:它们不会默默地安装东西,它们只是提示Android'd Package Manager。
Joaquin Iurchuk '18

Answers:


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

13
您的应用请求该权限,但是Android不会将该权限授予第三方应用。有关LogCat权限相关日志,请参见。
inazaruk 2011年

@inazaruk我读安装在/系统的应用程序/应用程序将获得全自动许可使用install_pakages但在描述这个职位似乎不工作。你能给我一些提示吗?
Zorb

3
如何通过反射调用installPackage?实际上我不能做Method method = aPackageManagerClass.getMethod(“ installPackage”,new Class [] {Uri.class,IPackageInstallObserver.class,Integer.TYPE,String.class}); 鉴于还隐藏了IPackageInstallObserver,有人可以帮我忙吗,在此处发布正确的代码进行反射。
Shilaghae

7
答案中的所有链接均无效。
Mayur Gangurde

13

我已经检查了亚行如何安装应用程序。
-将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)。
(通常安装,非root用户的设备),
它会执行以下操作:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
但这会产生错误:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
似乎该错误是由pm引发的,而不是AppInstall引发的。
因为SecurityException未被AppInstall捕获,并且该应用程序也不会崩溃。

我曾在有根设备(相同的应用程序和AppInstall)上尝试过相同的操作,它的工作原理很吸引人。
(也通常安装,不在/ system或其他任何系统中)
AppInstall甚至没有询问root权限。
但是,那是因为外壳是永远#的,而不是$在该设备上。

顺便说一句,您需要root才能在/ system中安装应用程序,对吗?
我在无根设备上尝试了adb remount并得到了:
remount failed: Operation not permitted.
这就是为什么我无法在无根设备上尝试/ system的原因。

结论:您应该使用有根设备
希望对您有所帮助:)


我似乎无法使它正常工作。有趣的是,该命令在ADB Shell中运行良好,然后在我尝试以编程方式运行它时似乎不起作用。
saulpower 2012年

是的,我也有同样的问题-可在shell中使用,但无法通过我的应用程序调用,即使我通过调用也是如此su
velis

还有其他方法可以在Google设备上工作,例如获得超级管理员权限?
拉梅什·库玛

如果您需要超级管理员权限,则应该:1)根设备,2)在系统分区上安装应用程序,3)或使用与操作系统本身相同的密钥对应用程序进行签名。
FrankkieNL

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作为系统应用程序安装,该应用程序需要root用户(但是,在安装更新程序应用程序后,它似乎没有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


“由于某种原因,它不适用于简单的调试版本”您是说它在发行版中还是在其他一些“简单”的调试版本中起作用?
JM Lord

1
@JMLord它适用于签名发行版,但不适用于签名和未签名的调试版本-我感到奇怪的是,它不适用于签名的调试版本,但我没有时间进行调查。但是,系统logcat日志对于确定是否已安装APK非常重要。
鲍里斯·特鲁霍夫

确实,出于某种原因,安装发行版是获得INSTALL_PACKAGES权限的关键。该应用程序可以在priv-app的签名调试中运行,但是权限请求被拒绝。非常感谢!
JM Lord

@BorisTreukhov嘿,我可以与您核对packageName参数的用途吗?我将InputStream更改为FileInputStream,但收到此错误消息:无法解析/data/app/vmdl676191029.tmp/COSU

这些命令后如何安装系统priv app?
user2323471

8

你应该定义

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

在清单中,然后,如果您是在系统分区(/ system / app)中还是由制造商签署了应用程序,则将拥有INSTALL_PACKAGES权限。

我的建议是创建一个1.5兼容级别的小android项目,该项目用于通过反射调用installPackages并导出带有安装包和调用实际方法的方法的jar。然后,通过将jar导入项目中,就可以安装软件包了。


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

2
问题是关于安装没有root用户但具有系统“ INSTALL_PACKAGES”权限的应用程序。我在您的答案中看到“ su”,因此它需要root。
POMATu 2014年

非常感谢您的回答!我有相同的代码,但我使用的是“ adb install -r”而不是“ pm install -r”,它对我不起作用。您在这里节省了我很多时间!
Jeff.H

@弗拉德米尔我需要你的帮助。你能给我一点时间吗?我将非常感谢您
twana eng

4

我不知道如何执行此操作,因为那时没有人回答,而且我也没有找到有关此权限的文档。所以我找到了自己的解决方案。您的情况更糟,但这还是一个解决方案。

我安装了busybox,将777权限设置为/ data / app(我不在乎安全性)。然后只需从应用程序执行“ busybox安装”即可。这可行,但存在很大的安全漏洞。如果将权限设置为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清单文件中的权限。


您是否在棒棒糖和棉花糖上测试过此代码?对我来说,这似乎是一种很棒的方法,我想使用它
Farhad Faghihi

我已经测试了从ICS到Lollipop的测试
Hermann Poilpre

要查找的行是“您的应用程序必须是系统”。我很确定这可以在棒棒糖或其他任何东西上工作-前提是您的应用程序是“系统”,也就是说,您的应用程序具有系统权限(基本上是root)。但是在这种情况下,您也可以使用命令行安装程序。
Lassi Kinnunen

1
如何调用installPackage方法?意思是,如何获取一个IPackageInstallObserver?
phoebus '18

installFlags的值是多少?
Shivam Kumar

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 2014年

1
@ZeeShaNAbbAs生根问题解决后..谢谢
Sandeep P

1

先决条件:

您的APK需要由系统正确签名,如之前正确指出的那样。实现此目的的一种方法是自己构建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上进行了测试,效果很好。


我需要你的帮助。你能给我一点时间吗?我将非常感谢您
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 SDK 2.3和4.0上进行了测试。也许它将与早期版本一起使用。


它可以在4.1和4.0以及任何高于2.1(包括2.1)的android版本中使用。我现在正在使用4.0 SDK。您需要将其添加到/ system / app文件夹,否则您的应用将没有必需的系统级(不是root)权限。另外,我也可以使用此方法静默删除应用程序,请检查与删除相关的其他问题。
POMATu

是的,它可以工作,但是仅具有root的权限。并且无法将应用程序安装到非根目录设备上的系统/应用程序中。
АндрейМосквичёв

不是root用户,而是系统级权限。如果您是固件制造商,则可以将其添加到/ system / app。就我而言-我(我要求设备制造商将我的APK添加到固件中)。您将无法以任何其他方式静默安装应用程序-否则,这将是一个很大的安全漏洞。
POMATu

关于安全漏洞-我绝对同意。如果此方法适用于任何应用,这对我来说将是一个惊喜。如何在不生根的情况下将应用程序安装到/ system / app中?我不是制造商。
АндрейМосквичёв

1
没有root或刷新,您将无法进行。
POMATu


0

第三方应用程序无法轻松安装Android应用程序。但是,第三方应用程序可以要求Android OS安装应用程序。

因此,您应该定义以下内容:

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

可以在Android 6及更高版本上进行静默安装。使用Boris Treukhov答案中提供的功能,忽略帖子中的所有其他内容,也不需要root。

以设备管理员身份安装您的应用,您可以使用完整的信息亭模式,并在后台静默安装更新。




-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

这对我有用。我在shell终端上的ubuntu 12.04上运行它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.