PackageManager keeps track of who installed what.
Stores the package name of the installer app in packages.xml
diff --git a/api/current.xml b/api/current.xml
index f227605..643ea23 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -35526,6 +35526,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="true"
@@ -35821,7 +35834,7 @@
</method>
<method name="installPackage"
return="void"
- abstract="true"
+ abstract="false"
native="false"
synchronized="false"
static="false"
@@ -114343,6 +114356,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="false"
@@ -114635,6 +114661,8 @@
</parameter>
<parameter name="flags" type="int">
</parameter>
+<parameter name="installerPackageName" type="java.lang.String">
+</parameter>
</method>
<method name="isSafeMode"
return="boolean"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 04e69e3..ac62757 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -579,6 +579,7 @@
private void runInstall() {
int installFlags = 0;
+ String installerPackageName = null;
String opt;
while ((opt=nextOption()) != null) {
@@ -586,6 +587,13 @@
installFlags |= PackageManager.FORWARD_LOCK_PACKAGE;
} else if (opt.equals("-r")) {
installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
+ } else if (opt.equals("-i")) {
+ installerPackageName = nextOptionData();
+ if (installerPackageName == null) {
+ System.err.println("Error: no value specified for -i");
+ showUsage();
+ return;
+ }
} else {
System.err.println("Error: Unknown option: " + opt);
showUsage();
@@ -603,7 +611,8 @@
PackageInstallObserver obs = new PackageInstallObserver();
try {
- mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags);
+ mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
+ installerPackageName);
synchronized (obs) {
while (!obs.finished) {
@@ -812,7 +821,7 @@
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
System.err.println(" pm path PACKAGE");
- System.err.println(" pm install [-l] [-r] PATH");
+ System.err.println(" pm install [-l] [-r] [-i INSTALLER_PACKAGE_NAME] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
@@ -840,6 +849,7 @@
System.err.println("The install command installs a package to the system. Use");
System.err.println("the -l option to install the package with FORWARD_LOCK. Use");
System.err.println("the -r option to reinstall an exisiting app, keeping its data.");
+ System.err.println("the -i option to specify the installer package name.");
System.err.println("");
System.err.println("The uninstall command removes a package from the system. Use");
System.err.println("the -k option to keep the data and cache directories around");
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 72d9e3d..d235832 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -2326,15 +2326,26 @@
}
@Override
- public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags) {
+ public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
+ String installerPackageName) {
try {
- mPM.installPackage(packageURI, observer, flags);
+ mPM.installPackage(packageURI, observer, flags, installerPackageName);
} catch (RemoteException e) {
// Should never happen!
}
}
@Override
+ public String getInstallerPackageName(String packageName) {
+ try {
+ return mPM.getInstallerPackageName(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
+ @Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
try {
mPM.deletePackage(packageName, observer, flags);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bf963ff..57b84b2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -140,8 +140,11 @@
* @param observer a callback to use to notify when the package installation in finished.
* @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
* {@link #REPLACE_EXISITING_PACKAGE}
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
*/
- void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags);
+ void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
+ in String installerPackageName);
/**
* Delete a package.
@@ -152,6 +155,8 @@
*/
void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags);
+ String getInstallerPackageName(in String packageName);
+
void addPackageToPreferred(String packageName);
void removePackageFromPreferred(String packageName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e2f0ce4..18e4548 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1354,8 +1354,35 @@
*
* @see #installPackage(android.net.Uri)
*/
+ public void installPackage(
+ Uri packageURI, IPackageInstallObserver observer, int flags) {
+ installPackage(packageURI, observer, flags, null);
+ }
+
+ /**
+ * Install a package. Since this may take a little while, the result will
+ * be posted back to the given observer. An installation will fail if the calling context
+ * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
+ * package named in the package file's manifest is already installed, or if there's no space
+ * available on the device.
+ *
+ * @param packageURI The location of the package file to install. This can be a 'file:' or a
+ * 'content:' URI.
+ * @param observer An observer callback to get notified when the package installation is
+ * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
+ * called when that happens. observer may be null to indicate that no callback is desired.
+ * @param flags - possible values: {@link #FORWARD_LOCK_PACKAGE},
+ * {@link #REPLACE_EXISTING_PACKAGE}
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
+ *
+ * @see #installPackage(android.net.Uri)
+ *
+ * @hide
+ */
public abstract void installPackage(
- Uri packageURI, IPackageInstallObserver observer, int flags);
+ Uri packageURI, IPackageInstallObserver observer, int flags,
+ String installerPackageName);
/**
* Attempts to delete a package. Since this may take a little while, the result will
@@ -1374,6 +1401,15 @@
*/
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
+
+ /**
+ * Retrieve the package name of the application that installed a package. This identifies
+ * which market the package came from.
+ *
+ * @param packageName The name of the package to query
+ */
+ public abstract String getInstallerPackageName(String packageName);
+
/**
* Attempts to clear the user data directory of an application.
* Since this may take a little while, the result will
@@ -1483,7 +1519,7 @@
*
* @param packageURI The location of the package file to install
*
- * @see #installPackage(android.net.Uri, IPackageInstallObserver, int)
+ * @see #installPackage(android.net.Uri, IPackageInstallObserver, int, String)
*/
public void installPackage(Uri packageURI) {
installPackage(packageURI, null, 0);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1a11902..d3bb03c 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3234,20 +3234,27 @@
private final String mRootDir;
private final boolean mIsRom;
}
-
+
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
+ installPackage(packageURI, observer, flags, null);
+ }
+
+ /* Called when a downloaded package installation has been confirmed by the user */
+ public void installPackage(
+ final Uri packageURI, final IPackageInstallObserver observer, final int flags,
+ final String installerPackageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES, null);
-
+
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
PackageInstalledInfo res;
synchronized (mInstallLock) {
- res = installPackageLI(packageURI, flags, true);
+ res = installPackageLI(packageURI, flags, true, installerPackageName);
}
if (observer != null) {
try {
@@ -3295,7 +3302,7 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
res.name = pkgName;
@@ -3331,7 +3338,8 @@
destResourceFile, pkg,
newPackage,
true,
- forwardLocked,
+ forwardLocked,
+ installerPackageName,
res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
@@ -3352,7 +3360,8 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
+
PackageParser.Package oldPackage;
// First find the old package info and check signatures
synchronized(mPackages) {
@@ -3367,11 +3376,11 @@
replaceSystemPackageLI(oldPackage,
tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, res);
+ newInstall, installerPackageName, res);
} else {
replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, res);
+ newInstall, installerPackageName, res);
}
}
@@ -3379,11 +3388,17 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean updatedSettings = false;
+
+ String oldInstallerPackageName = null;
+ synchronized (mPackages) {
+ oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
+ }
+
int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE;
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
@@ -3412,6 +3427,7 @@
newPackage,
true,
forwardLocked,
+ installerPackageName,
res);
updatedSettings = true;
}
@@ -3456,7 +3472,7 @@
Uri.fromFile(new File(deletedPackage.mPath)),
isForwardLocked(deletedPackage)
? PackageManager.FORWARD_LOCK_PACKAGE
- : 0, false);
+ : 0, false, oldInstallerPackageName);
}
}
}
@@ -3465,7 +3481,7 @@
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
boolean updatedSettings = false;
int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE |
@@ -3515,7 +3531,8 @@
destResourceFile, pkg,
newPackage,
true,
- forwardLocked,
+ forwardLocked,
+ installerPackageName,
res);
updatedSettings = true;
}
@@ -3542,6 +3559,8 @@
synchronized(mPackages) {
if(updatedSettings) {
mSettings.enableSystemPackageLP(packageName);
+ mSettings.setInstallerPackageName(packageName,
+ oldPkgSetting.installerPackageName);
}
mSettings.writeLP();
}
@@ -3555,7 +3574,7 @@
PackageParser.Package newPackage,
boolean replacingExistingPackage,
boolean forwardLocked,
- PackageInstalledInfo res) {
+ String installerPackageName, PackageInstalledInfo res) {
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
@@ -3602,6 +3621,7 @@
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+ mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
mSettings.writeLP();
@@ -3609,7 +3629,7 @@
}
private PackageInstalledInfo installPackageLI(Uri pPackageURI,
- int pFlags, boolean newInstall) {
+ int pFlags, boolean newInstall, String installerPackageName) {
File tmpPackageFile = null;
String pkgName = null;
boolean forwardLocked = false;
@@ -3722,13 +3742,13 @@
replacePackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall,
+ pkg, forwardLocked, newInstall, installerPackageName,
res);
} else {
installNewPackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall,
+ pkg, forwardLocked, newInstall, installerPackageName,
res);
}
} finally {
@@ -4546,6 +4566,16 @@
}
}
+ public String getInstallerPackageName(String packageName) {
+ synchronized (mPackages) {
+ PackageSetting pkg = mSettings.mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.installerPackageName;
+ }
+ }
+
public int getApplicationEnabledSetting(String appPackageName) {
synchronized (mPackages) {
PackageSetting pkg = mSettings.mPackages.get(appPackageName);
@@ -5195,6 +5225,9 @@
HashSet<String> enabledComponents = new HashSet<String>(0);
int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
int installStatus = PKG_INSTALL_COMPLETE;
+
+ /* package name of the app that installed this package */
+ String installerPackageName;
PackageSettingBase(String name, File codePath, File resourcePath,
int pVersionCode, int pkgFlags) {
@@ -5207,6 +5240,14 @@
this.versionCode = pVersionCode;
}
+ public void setInstallerPackageName(String packageName) {
+ installerPackageName = packageName;
+ }
+
+ String getInstallerPackageName() {
+ return installerPackageName;
+ }
+
public void setInstallStatus(int newStatus) {
installStatus = newStatus;
}
@@ -5437,6 +5478,19 @@
}
}
+ void setInstallerPackageName(String pkgName,
+ String installerPkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ p.setInstallerPackageName(installerPkgName);
+ }
+ }
+
+ String getInstallerPackageName(String pkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ return (p == null) ? null : p.getInstallerPackageName();
+ }
+
int getInstallStatus(String pkgName) {
PackageSetting p = mPackages.get(pkgName);
if(p != null) {
@@ -5912,6 +5966,9 @@
if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
serializer.attribute(null, "installStatus", "false");
}
+ if (pkg.installerPackageName != null) {
+ serializer.attribute(null, "installer", pkg.installerPackageName);
+ }
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
serializer.startTag(null, "perms");
@@ -5946,6 +6003,7 @@
}
serializer.endTag(null, "enabled-components");
}
+
serializer.endTag(null, "package");
}
@@ -6267,6 +6325,7 @@
String codePathStr = null;
String resourcePathStr = null;
String systemStr = null;
+ String installerPackageName = null;
int pkgFlags = 0;
String timeStampStr;
long timeStamp = 0;
@@ -6287,6 +6346,7 @@
}
}
systemStr = parser.getAttributeValue(null, "system");
+ installerPackageName = parser.getAttributeValue(null, "installer");
if (systemStr != null) {
if ("true".equals(systemStr)) {
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
@@ -6360,6 +6420,7 @@
+ parser.getPositionDescription());
}
if (packageSetting != null) {
+ packageSetting.installerPackageName = installerPackageName;
final String enabledStr = parser.getAttributeValue(null, "enabled");
if (enabledStr != null) {
if (enabledStr.equalsIgnoreCase("true")) {
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index ea190e2..20929a3 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -286,7 +286,12 @@
@Override
public void installPackage(Uri packageURI, IPackageInstallObserver observer,
- int flags) {
+ int flags, String installerPackageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();
}