diff options
-rw-r--r-- | api/current.xml | 56 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 14 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 25 | ||||
-rwxr-xr-x | core/tests/coretests/src/android/content/pm/PackageManagerTests.java | 159 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 96 | ||||
-rw-r--r-- | test-runner/src/android/test/mock/MockPackageManager.java | 11 |
7 files changed, 342 insertions, 22 deletions
diff --git a/api/current.xml b/api/current.xml index 85b367d..c0dcfe6 100644 --- a/api/current.xml +++ b/api/current.xml @@ -45952,6 +45952,19 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getPackageObbPaths" + 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="getPackagesForUid" return="java.lang.String[]" abstract="true" @@ -46423,6 +46436,21 @@ <parameter name="flags" type="int"> </parameter> </method> +<method name="setPackageObbPaths" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +<parameter name="paths" type="java.lang.String[]"> +</parameter> +</method> <field name="COMPONENT_ENABLED_STATE_DEFAULT" type="int" transient="false" @@ -159105,6 +159133,19 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getPackageObbPaths" + 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="getPackagesForUid" return="java.lang.String[]" abstract="false" @@ -159589,6 +159630,21 @@ <parameter name="path" type="java.lang.String"> </parameter> </method> +<method name="setPackageObbPaths" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="packageName" type="java.lang.String"> +</parameter> +<parameter name="paths" type="java.lang.String[]"> +</parameter> +</method> </class> <class name="MockResources" extends="android.content.res.Resources" diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 7e7cd7a..18ab478 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2700,14 +2700,24 @@ class ContextImpl extends Context { } @Override - public void setPackageObbPath(String packageName, String path) { + public void setPackageObbPaths(String packageName, String[] paths) { try { - mPM.setPackageObbPath(packageName, path); + mPM.setPackageObbPaths(packageName, paths); } catch (RemoteException e) { // Should never happen! } } + @Override + public String[] getPackageObbPaths(String packageName) { + try { + return mPM.getPackageObbPaths(packageName); + } catch (RemoteException e) { + // Should never happen! + } + return null; + } + private final ContextImpl mContext; private final IPackageManager mPM; diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 4cff3bb..44b0c96 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -322,5 +322,6 @@ interface IPackageManager { boolean setInstallLocation(int loc); int getInstallLocation(); - void setPackageObbPath(String packageName, String path); + void setPackageObbPaths(in String packageName, in String[] paths); + String[] getPackageObbPaths(in String packageName); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index b5d1653..a1c29f7 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2273,15 +2273,30 @@ public abstract class PackageManager { String packageName, IPackageMoveObserver observer, int flags); /** - * Sets the Opaque Binary Blob (OBB) file location. + * Sets the Opaque Binary Blob (OBB) file path associated with a package + * name. The caller must have the + * {@link android.Manifest.permission#INSTALL_PACKAGES} permission. * <p> * NOTE: The existence or format of this file is not currently checked, but * it may be in the future. * * @param packageName Name of the package with which to associate the .obb - * file - * @param path Path on the filesystem to the .obb file - * @hide + * file. + * @param paths Arrays of paths on the filesystem to the .obb files + * associated with the package. + * @see #getPackageObbPaths(String) + */ + public abstract void setPackageObbPaths(String packageName, String[] paths); + + /** + * Gets the Opaque Binary Blob (OBB) file path associated with the package. + * The caller must be the owner of the package queried or have the + * {@link android.Manifest.permission#INSTALL_PACKAGES} permission. + * + * @param packageName Name of the package with which to associate the .obb + * file. + * @return array of paths to .obb files associated with the package + * @see #setPackageObbPaths(String, String[]) */ - public abstract void setPackageObbPath(String packageName, String path); + public abstract String[] getPackageObbPaths(String packageName); } diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index d5f385b..c8a4593 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -47,6 +47,7 @@ import android.util.Log; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; public class PackageManagerTests extends AndroidTestCase { private static final boolean localLOGV = true; @@ -2838,6 +2839,164 @@ public class PackageManagerTests extends AndroidTestCase { installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true, fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED); } + + @LargeTest + public void testPackageObbPaths_Nonexistent() { + try { + final PackageManager pm = getPm(); + + // Invalid Java package name. + pm.getPackageObbPaths("=non-existent"); + + fail("Should not be able to get package OBB paths for non-existent package"); + } catch (IllegalArgumentException e) { + // pass + } + } + + @LargeTest + public void testPackageObbPaths_Initial() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + assertEquals("Initial obb paths should be null", + null, pm.getPackageObbPaths(ip.pkg.packageName)); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_Null() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + pm.setPackageObbPaths(ip.pkg.packageName, null); + + assertEquals("Returned paths should be null", + null, pm.getPackageObbPaths(ip.pkg.packageName)); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_Empty() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + final String[] paths = new String[0]; + + pm.setPackageObbPaths(ip.pkg.packageName, paths); + + assertEquals("Empty list should be interpreted as null", + null, pm.getPackageObbPaths(ip.pkg.packageName)); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_Single() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + final String[] paths = new String[] { + "/example/test", + }; + + pm.setPackageObbPaths(ip.pkg.packageName, paths.clone()); + + assertTrue("Previously set paths should be the same as the returned paths.", + Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName))); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_Multiple() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + final String[] paths = new String[] { + "/example/test1", + "/example/test2", + }; + + pm.setPackageObbPaths(ip.pkg.packageName, paths.clone()); + + assertTrue("Previously set paths should be the same as the returned paths.", + Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName))); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_Twice() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + final String[] paths = new String[] { + "/example/test1", + "/example/test2", + }; + + pm.setPackageObbPaths(ip.pkg.packageName, paths.clone()); + + assertTrue("Previously set paths should be the same as the returned paths.", + Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName))); + + paths[0] = "/example/test3"; + pm.setPackageObbPaths(ip.pkg.packageName, paths.clone()); + + assertTrue("Previously set paths should be the same as the returned paths.", + Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName))); + } finally { + cleanUpInstall(ip); + } + } + + @LargeTest + public void testPackageObbPaths_ReplacePackage() { + InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false); + + try { + final PackageManager pm = getPm(); + + final String[] paths = new String[] { + "/example/test1", + "/example/test2", + }; + + pm.setPackageObbPaths(ip.pkg.packageName, paths.clone()); + + Log.i(TAG, "Creating replaceReceiver"); + final GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName); + + final int flags = PackageManager.INSTALL_REPLACE_EXISTING; + invokeInstallPackage(ip.packageURI, flags, receiver); + assertInstall(ip.pkg, flags, ip.pkg.installLocation); + + assertTrue("Previously set paths should be the same as the returned paths.", + Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName))); + } finally { + cleanUpInstall(ip); + } + } /*---------- Recommended install location tests ----*/ /* * TODO's diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index b0f3a23..ead9f22 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -102,6 +102,7 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.lang.reflect.Array; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -4577,16 +4578,52 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.sendMessage(msg); } - public void setPackageObbPath(String packageName, String path) { + public void setPackageObbPaths(String packageName, String[] paths) { if (DEBUG_OBB) - Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path); - PackageSetting pkgSetting; + Log.v(TAG, "Setting .obb paths for " + packageName + " to: " + Arrays.toString(paths)); final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingPermission( android.Manifest.permission.INSTALL_PACKAGES); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + if (!allowedByPermission) { + throw new SecurityException("Permission denial: attempt to set .obb file from pid=" + + Binder.getCallingPid()); + } synchronized (mPackages) { - pkgSetting = mSettings.mPackages.get(packageName); + final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); + if (pkgSetting == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + + if (paths != null) { + if (paths.length == 0) { + // Don't bother storing an empty array. + paths = null; + } else { + // Don't allow the caller to manipulate our copy of the + // list. + paths = paths.clone(); + } + } + + // Only write settings file if the new and old settings are not the + // same. + if (!Arrays.equals(paths, pkgSetting.obbPathStrings)) { + pkgSetting.obbPathStrings = paths; + mSettings.writeLP(); + } + } + } + + public String[] getPackageObbPaths(String packageName) { + if (DEBUG_OBB) + Log.v(TAG, "Getting .obb paths for " + packageName); + final int uid = Binder.getCallingUid(); + final int permission = mContext.checkCallingPermission( + android.Manifest.permission.INSTALL_PACKAGES); + final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + synchronized (mPackages) { + final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -4595,8 +4632,7 @@ class PackageManagerService extends IPackageManager.Stub { + Binder.getCallingPid() + ", uid=" + uid + ", package uid=" + pkgSetting.userId); } - pkgSetting.obbPathString = path; - mSettings.writeLP(); + return pkgSetting.obbPathStrings; } } @@ -7165,7 +7201,7 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" codePath="); pw.println(ps.codePathString); pw.print(" resourcePath="); pw.println(ps.resourcePathString); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); - pw.print(" obbPath="); pw.println(ps.obbPathString); + pw.print(" obbPaths="); pw.println(Arrays.toString(ps.obbPathStrings)); pw.print(" versionCode="); pw.println(ps.versionCode); if (ps.pkg != null) { pw.print(" versionName="); pw.println(ps.pkg.mVersionName); @@ -7728,7 +7764,7 @@ class PackageManagerService extends IPackageManager.Stub { File resourcePath; String resourcePathString; String nativeLibraryPathString; - String obbPathString; + String[] obbPathStrings; long timeStamp; long firstInstallTime; long lastUpdateTime; @@ -8749,8 +8785,15 @@ class PackageManagerService extends IPackageManager.Stub { if (pkg.installerPackageName != null) { serializer.attribute(null, "installer", pkg.installerPackageName); } - if (pkg.obbPathString != null) { - serializer.attribute(null, "obbPath", pkg.obbPathString); + if (pkg.obbPathStrings != null && pkg.obbPathStrings.length > 0) { + int N = pkg.obbPathStrings.length; + serializer.startTag(null, "obbs"); + for (int i = 0; i < N; i++) { + serializer.startTag(null, "obb"); + serializer.attribute(null, "path", pkg.obbPathStrings[i]); + serializer.endTag(null, "obb"); + } + serializer.endTag(null, "obbs"); } pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { @@ -9154,7 +9197,6 @@ class PackageManagerService extends IPackageManager.Stub { String codePathStr = null; String resourcePathStr = null; String nativeLibraryPathStr = null; - String obbPathStr = null; String systemStr = null; String installerPackageName = null; String uidError = null; @@ -9174,7 +9216,6 @@ class PackageManagerService extends IPackageManager.Stub { codePathStr = parser.getAttributeValue(null, "codePath"); resourcePathStr = parser.getAttributeValue(null, "resourcePath"); nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); - obbPathStr = parser.getAttributeValue(null, "obbPath"); version = parser.getAttributeValue(null, "version"); if (version != null) { try { @@ -9299,7 +9340,6 @@ class PackageManagerService extends IPackageManager.Stub { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; packageSetting.nativeLibraryPathString = nativeLibraryPathStr; - packageSetting.obbPathString = obbPathStr; final String enabledStr = parser.getAttributeValue(null, "enabled"); if (enabledStr != null) { if (enabledStr.equalsIgnoreCase("true")) { @@ -9347,6 +9387,8 @@ class PackageManagerService extends IPackageManager.Stub { readGrantedPermissionsLP(parser, packageSetting.grantedPermissions); packageSetting.permissionsFixed = true; + } else if (tagName.equals("obbs")) { + readObbPathsLP(packageSetting, parser); } else { reportSettingsProblem(Log.WARN, "Unknown element under <package>: " @@ -9551,6 +9593,34 @@ class PackageManagerService extends IPackageManager.Stub { } } + private void readObbPathsLP(PackageSettingBase packageSetting, XmlPullParser parser) + throws XmlPullParserException, IOException { + final List<String> obbPaths = new ArrayList<String>(); + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String tagName = parser.getName(); + if (tagName.equals("obb")) { + final String path = parser.getAttributeValue(null, "path"); + obbPaths.add(path); + } else { + reportSettingsProblem(Log.WARN, "Unknown element under <obbs>: " + + parser.getName()); + } + XmlUtils.skipCurrentTag(parser); + } + if (obbPaths.size() == 0) { + return; + } else { + packageSetting.obbPathStrings = obbPaths.toArray(new String[obbPaths.size()]); + } + } + // Returns -1 if we could not find an available UserId to assign private int newUserIdLP(Object obj) { // Let's be stupidly inefficient for now... diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index f0cbaa0..4a18b3e 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -490,8 +490,17 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } - @Override public void setPackageObbPath(String packageName, String path) { throw new UnsupportedOperationException(); } + + @Override + public void setPackageObbPaths(String packageName, String[] paths) { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getPackageObbPaths(String packageName) { + throw new UnsupportedOperationException(); + } } |