安卓预装NDK应用程序

9
我们正在尝试将一个NDK应用程序预安装到/system/app目录中。如果我在ZIP文件管理器中打开apk文件,.so文件位于lib目录中。然而,当我们预安装apk文件时,apk的.so文件没有被复制到system/lib目录中,导致在设备上启动应用程序时失败。
请问有人能告诉我在Android.mk中应该设置什么,以便从APK文件中提取.so文件并将其复制到system/lib目录中?我们需要将应用程序包含在系统镜像中。
非常感谢任何反馈。
谢谢, artsylar

从技术上讲,我认为.so文件应该被复制到/data/data/com.yourpackage.name/lib目录中,但是我遇到了同样的问题,即预安装的应用程序没有将其从APK中复制出来。 - devunwired
我们所做的就是使用任何zip工具(如7zip)手动从APK中解压so文件。然后,我们创建了一个make文件,在编译Android源代码时将文件复制到/out/..../system/lib目录中。在我们的情况下,我们希望将其包含在ROM映像中,因为它是本地应用程序所需的,这就是为什么我们需要将其复制到/system/lib目录中的原因。 - artsylar
你可以参考这个论坛https://groups.google.com/group/android-ndk/browse_thread/thread/2d08a95b3038e532?hl=ja,他们遇到了和我们一样的问题。 - artsylar
是的,看起来这是设计上的。我今天正在测试将它放置在 data/app 目录中(另一个将自动解压缩的位置)是否会产生同样的效果。如果有效,我可能会发布为一个答案。 - devunwired
4个回答

4
我有同样的需求,在经过两天的繁重研究后,我找到了解决这个问题的办法。但这不是一件简单的事情,需要你能够修改Android系统代码。
通俗易懂地说,PackageManagerService防止系统应用程序解压本地二进制文件(.so文件),除非它们已被更新。因此,唯一解决这个问题的方法是修改PMS.java文件(因为尝试解决这个问题让我感到非常糟糕)。
在系统第一次启动时,我编写了一个isPackageNative(PackageParser.Package pkg)函数来检查每个系统包是否有本地二进制文件。
    private boolean isPackageNative(PackageParser.Package pkg) throws IOException {
    final ZipFile zipFile = new ZipFile(pkg.mPath);
    final Enumeration<? extends ZipEntry> privateZipEntries = zipFile.entries();
    while (privateZipEntries.hasMoreElements()) {
        final ZipEntry zipEntry = privateZipEntries.nextElement();
        final String zipEntryName = zipEntry.getName();
        if(true) Log.e(TAG, "    Zipfile entry:"+zipEntryName);
        if (zipEntryName.endsWith(".so")) {
            zipFile.close();
            return true;
        }
    }
    zipFile.close();
    return false;
  }

此函数检查每个软件包是否有本地库,如果有,则解压缩。PMS在scanPackageLI(...)中进行此检查。在该方法中搜索以下代码:

   if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg))

并添加isPackageNative(pkg)检查。还需要进行其他一些小的修改,但是一旦有了这个方向,您可能会想出来。希望对您有所帮助!


哇,谢谢!这是目前为止最好的答案,虽然我现在没有机会尝试它。但它看起来是最好的方法,所以我会接受这个答案。谢谢! - artsylar

2

我认为默认情况下您无法这样做,因为Android的/system分区被挂载为只读!您需要一个已root的手机才能通过以下命令以写入权限挂载/system:

mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system.

所以,如果您有一部已经root的手机,您可以在您的应用程序中添加以下代码:
Process p;  
try {  
    // Preform su to get root privledges
    p = Runtime.getRuntime().exec("su");
    // Attempt to write a file to a root-only  
    DataOutputStream os = new DataOutputStream(p.getOutputStream()); 
    // gain root privileges 
    os.writeBytes("mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system\n");
    // do here the copy operation you want in /system/lib file, for example:
    os.writeBytes("mv /sdcard/mylib.so /system/lib/\n");

     // Close the terminal  
     os.writeBytes("exit\n");  
     os.flush();  

 } catch (IOException e) {  
    toastMessage("could not get root access");  
 }

否则,您必须遵循digitalmouse12提供的解决方案。

这并不是真正相关的,因为你谈论的是在手机上修改安装,但发帖者谈论的是在系统镜像中包含一些要在手机安装之前安装的内容。 - Chris Stratton
谢谢Thanasis。然而,Chris是正确的。我想知道的是如何将预构建的apk文件与捆绑的.so文件预安装到系统映像中。 - artsylar
是的,我现在明白问题了,但我不知道解决方案。如果我找到了什么,我会告诉你! :) - Thanasis Petsas

1
你需要自己执行 "adb push" 命令来传输 .so 文件。此外,你不一定需要将库文件推送到 system/lib 目录下(该目录可能会拒绝你的权限)。大多数人会将其推送到 data/app 目录下,然后通过发出命令进行加载。
System.load("/data/app/<libName>.so");

感谢@digitalmouse12的评论。然而,我们需要将应用程序集成到系统映像中,这意味着我们必须在不使用adb的情况下预安装它。 - artsylar
我发现了这篇帖子链接,它说:“在第一次启动序列期间(例如,在模拟器启动时进行-wipe-data,或在设备上进行出厂设置后),系统将扫描/system/app/<packagename>.apk下的捆绑应用程序,并逐个安装它们。”。 - artsylar
这是否意味着库文件(*.so)也将被提取到/system/lib目录下?但为什么它还说“与系统捆绑的应用程序应该将其系统库放置在/system/lib下”? - artsylar

0

可能有文档可以查阅,但如果找不到,我建议找出一个带有相关 jni 库.so 的预安装应用程序,并检查 Android 源码或相应的系统镜像或 update.zip,以了解它是如何处理的。

换句话说,通过例子进行编程...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接