diff options
5 files changed, 71 insertions, 3 deletions
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 4bbbdee797e9..11f0eb626964 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -482,6 +482,11 @@ interface IPackageManager { boolean performDexOptMode(String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force); + /** + * Ask the package manager to dump profiles associated with a package. + */ + void dumpProfiles(String packageName); + void forceDexOpt(String packageName); /** diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index a7a3cb59f90d..419c3d85599d 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -157,9 +157,7 @@ public class InstallerConnection { sharedLibraries); } - public boolean mergeProfiles(int uid, String pkgName) throws InstallerException { - final String[] res = execute("merge_profiles", uid, pkgName); - + private boolean safeParseBooleanResult(String[] res) throws InstallerException { if ((res == null) || (res.length != 2)) { throw new InstallerException("Invalid size result: " + Arrays.toString(res)); } @@ -172,6 +170,19 @@ public class InstallerConnection { return Boolean.parseBoolean(res[1]); } + public boolean mergeProfiles(int uid, String pkgName) throws InstallerException { + final String[] res = execute("merge_profiles", uid, pkgName); + + return safeParseBooleanResult(res); + } + + public boolean dumpProfiles(String gid, String packageName, String codePaths) + throws InstallerException { + final String[] res = execute("dump_profiles", gid, packageName, codePaths); + + return safeParseBooleanResult(res); + } + private boolean connect() { if (mSocket != null) { return true; diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 913c82428ec6..7b85a4f25cee 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -153,6 +153,11 @@ public final class Installer extends SystemService { return mInstaller.mergeProfiles(uid, pkgName); } + public boolean dumpProfiles(String gid, String packageName, String codePaths) + throws InstallerException { + return mInstaller.dumpProfiles(gid, packageName, codePaths); + } + public void idmap(String targetApkPath, String overlayApkPath, int uid) throws InstallerException { mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index eb4d7557ac18..95e008765b51 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7458,6 +7458,45 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override + public void dumpProfiles(String packageName) { + PackageParser.Package pkg; + synchronized (mPackages) { + pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + } + /* Only the shell or the app user should be able to dump profiles. */ + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SHELL_UID && callingUid != pkg.applicationInfo.uid) { + throw new SecurityException("dumpProfiles"); + } + + synchronized (mInstallLock) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles"); + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + try { + final File codeFile = new File(pkg.applicationInfo.getCodePath()); + List<String> allCodePaths = Collections.EMPTY_LIST; + if (codeFile != null && codeFile.exists()) { + try { + final PackageLite codePkg = PackageParser.parsePackageLite(codeFile, 0); + allCodePaths = codePkg.getAllCodePaths(); + } catch (PackageParserException e) { + // Well, we tried. + } + } + String gid = Integer.toString(sharedGid); + String codePaths = TextUtils.join(";", allCodePaths); + mInstaller.dumpProfiles(gid, packageName, codePaths); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to dump profiles", e); + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + @Override public void forceDexOpt(String packageName) { enforceSystemOrRoot("forceDexOpt"); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index beff8fc264a5..05f5b8f1ac6c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -105,6 +105,8 @@ class PackageManagerShellCommand extends ShellCommand { return runInstallWrite(); case "compile": return runCompile(); + case "dump-profiles": + return runDumpProfiles(); case "list": return runList(); case "uninstall": @@ -387,6 +389,12 @@ class PackageManagerShellCommand extends ShellCommand { } } + private int runDumpProfiles() throws RemoteException { + String packageName = getNextArg(); + mInterface.dumpProfiles(packageName); + return 0; + } + private int runList() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final String type = getNextArg(); |