Skip to content

feat: adding package lister with app name and versions#13

Open
gmegidish wants to merge 1 commit intomainfrom
feat-adding-package-lister-with-versions
Open

feat: adding package lister with app name and versions#13
gmegidish wants to merge 1 commit intomainfrom
feat-adding-package-lister-with-versions

Conversation

@gmegidish
Copy link
Copy Markdown
Member

@gmegidish gmegidish commented Mar 27, 2026

Summary by cubic

Adds a standalone package lister runnable via app_process that outputs a JSON array of installed apps with package name, app name, and version. Useful for inspecting devices from the shell without launching an app.

  • New Features
    • Introduces com.mobilenext.devicekit.PackageLister as a shell entry point (adb shell CLASSPATH=/path/to/classes.dex app_process / com.mobilenext.devicekit.PackageLister).
    • Fetches installed packages via ServiceManager + IPackageManager for user 0.
    • Resolves app labels via nonLocalizedLabel, then labelRes (using a temporary AssetManager), with fallback to the package name; outputs packageName, appName, version to stdout.

Written for commit facfcb5. Summary will update on new commits.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

Walkthrough

A new standalone Java class com.mobilenext.devicekit.PackageLister was added with a public static void main(String[] args) entry point. The class uses reflection to access Android's hidden ServiceManager and retrieves the list of installed packages via IPackageManager. It processes each package to construct a JSON array containing package metadata: packageName, version (from versionName), and appName (with fallback to package name). Label resolution attempts to extract user-visible names from package resources using AssetManager and Resources. The output is printed to stdout as JSON, or error details are printed to stderr with exit code 1 on failure.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a new package lister feature that includes app names and versions, which directly matches the changeset.
Description check ✅ Passed The description is clearly related to the changeset, providing detailed context about the new PackageLister class, its purpose, and implementation details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-adding-package-lister-with-versions

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/com/mobilenext/devicekit/PackageLister.java">

<violation number="1" location="app/src/main/java/com/mobilenext/devicekit/PackageLister.java:41">
P2: Avoid hard-coding userId=0 when querying installed packages; it can return the wrong package set on multi-user devices.</violation>

<violation number="2" location="app/src/main/java/com/mobilenext/devicekit/PackageLister.java:61">
P1: Close `AssetManager` after use; creating one per package without closing can leak native resources.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

displayName = appInfo.nonLocalizedLabel.toString();
} else if (appInfo.labelRes != 0 && appInfo.sourceDir != null) {
try {
AssetManager assets = AssetManager.class.getDeclaredConstructor().newInstance();
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Close AssetManager after use; creating one per package without closing can leak native resources.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/mobilenext/devicekit/PackageLister.java, line 61:

<comment>Close `AssetManager` after use; creating one per package without closing can leak native resources.</comment>

<file context>
@@ -0,0 +1,88 @@
+                        displayName = appInfo.nonLocalizedLabel.toString();
+                    } else if (appInfo.labelRes != 0 && appInfo.sourceDir != null) {
+                        try {
+                            AssetManager assets = AssetManager.class.getDeclaredConstructor().newInstance();
+                            Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
+                            addAssetPath.invoke(assets, appInfo.sourceDir);
</file context>
Fix with Cubic


// Call getInstalledPackages(flags, userId)
Method getInstalledPackages = ipm.getClass().getMethod("getInstalledPackages", long.class, int.class);
Object parceledList = getInstalledPackages.invoke(ipm, 0L, 0);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Avoid hard-coding userId=0 when querying installed packages; it can return the wrong package set on multi-user devices.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/mobilenext/devicekit/PackageLister.java, line 41:

<comment>Avoid hard-coding userId=0 when querying installed packages; it can return the wrong package set on multi-user devices.</comment>

<file context>
@@ -0,0 +1,88 @@
+
+            // Call getInstalledPackages(flags, userId)
+            Method getInstalledPackages = ipm.getClass().getMethod("getInstalledPackages", long.class, int.class);
+            Object parceledList = getInstalledPackages.invoke(ipm, 0L, 0);
+
+            // ParceledListSlice.getList()
</file context>
Fix with Cubic

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/src/main/java/com/mobilenext/devicekit/PackageLister.java (1)

60-70: Close the per-package AssetManager.

AssetManager is AutoCloseable and exposes close(). Since this loop allocates one per package, not closing it retains native resources until process exit; wrap the label lookup in finally. (android.googlesource.com)

♻️ Proposed fix
-                            AssetManager assets = AssetManager.class.getDeclaredConstructor().newInstance();
-                            Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
-                            addAssetPath.invoke(assets, appInfo.sourceDir);
-                            Resources res = new Resources(assets, new DisplayMetrics(), new Configuration());
-                            String label = res.getString(appInfo.labelRes);
-                            if (label != null && !label.isEmpty()) {
-                                displayName = label;
-                            }
+                            AssetManager assets = AssetManager.class.getDeclaredConstructor().newInstance();
+                            try {
+                                Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
+                                addAssetPath.invoke(assets, appInfo.sourceDir);
+                                Resources res = new Resources(assets, new DisplayMetrics(), new Configuration());
+                                String label = res.getString(appInfo.labelRes);
+                                if (label != null && !label.isEmpty()) {
+                                    displayName = label;
+                                }
+                            } finally {
+                                assets.close();
+                            }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/mobilenext/devicekit/PackageLister.java` around lines
60 - 70, The created per-package AssetManager in the try block (AssetManager
assets = AssetManager.class.getDeclaredConstructor().newInstance(); used with
addAssetPath and Resources) is not closed and leaks native resources; update the
code around AssetManager/assets (and the label lookup that uses appInfo.labelRes
and Resources) to use try-with-resources or ensure assets.close() is called in a
finally block after obtaining the label, so each AssetManager is closed for
every package iteration before continuing and displayName assignment remains
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/mobilenext/devicekit/PackageLister.java`:
- Around line 39-41: The reflection call in PackageLister that retrieves
getInstalledPackages on ipm currently assumes the signature
getInstalledPackages(long,int) and hardcodes userId 0, which will fail on older
Android (e.g., Android 10) that exposes getInstalledPackages(int,int) and
ignores multi-user installs; update the logic in PackageLister to try a fallback
chain: first attempt ipm.getClass().getMethod("getInstalledPackages",
long.class, int.class) and invoke it if present, then catch
NoSuchMethodException and try ipm.getClass().getMethod("getInstalledPackages",
int.class, int.class) and invoke that instead, mapping the long argument to an
int when using the older signature; also add a parameter to the PackageLister
API (or method where this reflection occurs) to accept a targetUserId instead of
hardcoding 0 and pass that value when invoking either signature so packages for
the requested user are returned.

---

Nitpick comments:
In `@app/src/main/java/com/mobilenext/devicekit/PackageLister.java`:
- Around line 60-70: The created per-package AssetManager in the try block
(AssetManager assets =
AssetManager.class.getDeclaredConstructor().newInstance(); used with
addAssetPath and Resources) is not closed and leaks native resources; update the
code around AssetManager/assets (and the label lookup that uses appInfo.labelRes
and Resources) to use try-with-resources or ensure assets.close() is called in a
finally block after obtaining the label, so each AssetManager is closed for
every package iteration before continuing and displayName assignment remains
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e28ae274-308c-405a-880e-584910ca1dba

📥 Commits

Reviewing files that changed from the base of the PR and between 6d53fb1 and facfcb5.

📒 Files selected for processing (1)
  • app/src/main/java/com/mobilenext/devicekit/PackageLister.java

Comment on lines +39 to +41
// Call getInstalledPackages(flags, userId)
Method getInstalledPackages = ipm.getClass().getMethod("getInstalledPackages", long.class, int.class);
Object parceledList = getInstalledPackages.invoke(ipm, 0L, 0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In AOSP, compare the declared signatures of android.content.pm.IPackageManager#getInstalledPackages on current master and android10-release, and confirm whether the userId parameter scopes the returned package list.

💡 Result:

The declared signatures of android.content.pm.IPackageManager#getInstalledPackages differ between AOSP current master and android10-release. In current AOSP master (refs/heads/main), the relevant method is: ParceledListSlice<PackageInfo> getInstalledPackages(@PackageManager.PackageInfoFlagsBits long flags, int userId) In android10-release (Android 10 / Q), the relevant method is: ParceledListSlice<PackageInfo> getInstalledPackages(int flags, in int userId) Both branches have the userId parameter as the second parameter. The userId parameter scopes the returned package list to packages installed for that specific user. In Android's multi-user system, packages can be installed per-user, and this method returns PackageInfo objects filtered to the specified userId, respecting per-user installation states. This is evident from the implementation pattern where ApplicationPackageManager passes userId to IPackageManager.getInstalledPackages, and PackageManagerService uses userId to filter results based on PackageUserState.isInstalled for that user.

Citations:


🏁 Script executed:

# Get the file content around the specified lines to understand context
head -60 "app/src/main/java/com/mobilenext/devicekit/PackageLister.java" | tail -40

Repository: mobile-next/devicekit-android

Length of output: 2090


Add fallback for different getInstalledPackages signatures across Android versions.

Lines 40–41 assume the method signature getInstalledPackages(long, int) (AOSP master), but older releases like Android 10 expose getInstalledPackages(int, int). This will raise NoSuchMethodException at runtime on those versions. Additionally, hardcoding userId=0 ignores packages installed for other users on multi-user devices.

Implement a try-fallback chain to attempt the master signature first, then fall back to the older (int, int) signature. Consider accepting the target user as a parameter instead of pinning it to 0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/mobilenext/devicekit/PackageLister.java` around lines
39 - 41, The reflection call in PackageLister that retrieves
getInstalledPackages on ipm currently assumes the signature
getInstalledPackages(long,int) and hardcodes userId 0, which will fail on older
Android (e.g., Android 10) that exposes getInstalledPackages(int,int) and
ignores multi-user installs; update the logic in PackageLister to try a fallback
chain: first attempt ipm.getClass().getMethod("getInstalledPackages",
long.class, int.class) and invoke it if present, then catch
NoSuchMethodException and try ipm.getClass().getMethod("getInstalledPackages",
int.class, int.class) and invoke that instead, mapping the long argument to an
int when using the older signature; also add a parameter to the PackageLister
API (or method where this reflection occurs) to accept a targetUserId instead of
hardcoding 0 and pass that value when invoking either signature so packages for
the requested user are returned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant