【问题标题】:Android Package manager has died with TransactionTooLargeExceptionAndroid 包管理器因 TransactionTooLargeException 而死
【发布时间】:2014-08-06 21:14:45
【问题描述】:

我的应用会读取所有已安装 APK 文件的列表,然后遍历列表以读取 APK 信息,但是它会引发 TransactionTooLargeException 异常。

从我在这里读到的http://developer.android.com/reference/android/os/TransactionTooLargeException.html,谷歌建议将大交易分解成小交易。然而,这似乎发生在遍历 APK 列表的中间。如果我捕捉到异常并继续它,其余的都可以正常工作。有没有办法在调用 getPackageInfo 时减少内存使用?即使在它已经返回之后,该调用是否会保留一些东西。

这是发生时的痕迹:

at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:89)
at com.myapp.appreader.getAppDetails(Appreader.java:207)
at com.myapp.appreader.collectData(Appreader.java:99)
at com.myapp.appreader.AppDataCollectionTask.run(AppDataCollectionTask.java:26)
at com.myapp.appreader.service.AppDataTaskExecutor$AppDataAsyncTask.executeTask(AppDataTaskExecutor.java:439) 
at com.myapp.appreader.service.AppDataTaskExecutor$AppDataAsyncTask.doInBackground(AppDataTaskExecutor.java:327)
at com.myapp.appreader.service.AppDataTaskExecutor$AppDataAsyncTask.doInBackground(AppDataTaskExecutor.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)\nCaused by: android.os.TransactionTooLargeExceptionat android.os.BinderProxy.transact(Native Method)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1538)
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:84)

【问题讨论】:

  • 尝试在每次调用时使用较小的标志列表。 IOW,不要在一次调用中询问所有可能的标志,而是尝试使用标志的子集进行两到三个调用。
  • 现在我在通话中有 7 个标志,是不是太大了?我将尝试将其拆分为 2-3 次调用,看看情况如何。现在的错误总是发生在循环中的第 74 个 APK 上。然而,在它之后还有更多,并且所有这些(以及之前的那些)都运行良好。
  • "现在我在通话中有 7 个标志,是不是太大了?" -- 取决于包的复杂程度。包中的组件和其他东西越多,结果集就越大。也许第 74 个应用程序只是一个非常复杂的应用程序。
  • 这很有趣。我想这是一个复杂的应用程序(谷歌地图)。但是我试图只调用谷歌地图的 getPackageInfo,它没有任何问题。所以显然循环也是异常的一个因素。一些资源没有足够快地释放。将循环分成几个较小的循环值得一试吗?
  • “显然循环也是异常的一个因素”——我没想到会这样,但我当然不能排除它。 “将循环分成几个更小的循环值得一试吗?” ——是的,只是因为你只有这么多的选择。 :-) 如果大小没有帮助(更少的标志),那么时间可能(通过循环更慢的迭代)。在那之后,我没有想法了。

标签: android exception transactions android-package-managers


【解决方案1】:

我找到了解决此问题的方法,并将其发布在here

简而言之,它会找到已安装应用程序的包名(使用 ADB),然后依次获取每个应用程序的信息。

【讨论】:

    【解决方案2】:

    Binder 事务有 1MB 的限制,这意味着大多数 IPC 调用的大小必须适中。

    如果您在从 PackageManager(例如,getPackageInfo())检索数据时遇到 TransactionTooLargeException 或类似的 Binder 故障,请尝试将您的请求拆分为多个调用,每次调用使用更少的标志(例如,GET_META_DATA)。希望这会将任何单个事务的大小减少到 1MB 限制以下。

    此外,如果您在 PackageManager 上使用返回多个结果的调用(例如,getInstalledPackages(),请尝试在该调用上请求 no 标志,然后分别检索每个包的值,以避免一次获得大量条目的大量数据。

    当然,只使用您需要的标志,特别是如果您的调用可能包含一些标志。 GET_META_DATA 是一个典型的例子:许多应用程序都使用它(例如,用于播放服务),但如果您不需要知道元数据信息,请不要请求它。

    【讨论】:

    • 为什么Android的原代码不能处理这样的请求?不应该是知道限制,划分查询并正确处理的人吗?我怎么知道有多少个应用程序,以便我可以决定何时将查询划分为多个查询?您能否展示一个与此代码具有相同功能的代码示例:packageManager.getInstalledPackages(0)
    • @androiddeveloper:“不应该是知道限制的那个,划分查询并正确处理吗?” - 欢迎您提出问题以尝试让他们改进这一点。 “我怎么知道有多少个应用程序”——打电话给getInstalledPackages(),没有任何标志,目标是每个条目的元数据最少,并希望最好。我不知道其他方法。
    • 但这就是我所做的。没有标志意味着0,不是吗?我仍然从至少一个用户那里得到了这个例外。关于举报谷歌,我确信我已经举报了。奇怪的。无论如何,再次搜索,我发现了这个:code.google.com/p/android/issues/detail?id=93717。它真的说他们已经在 Android 5.1 上修复了吗?
    • @androiddeveloper:“没有标志意味着 0,不是吗?” - 它应该是。 “我仍然从至少一个用户那里得到了这个例外”——:: 耸肩:: 尽可能优雅地失败,我猜。 “它真的说他们已经在 Android 5.1 上修复了它吗?”——这将是我对该问题的评论 #11 的解释。
    • 所以我对此无能为力......我想知道需要多少应用程序才能导致这种情况。当然,用户没有安装 1M 应用程序(这是最大值,如果每个应用程序信息占用 1B)...是否有可能我自己进行查询?检查 APKs 路径的文件夹?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 2021-10-22
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多