diff options
author | Dianne Hackborn <hackbod@google.com> | 2009-08-27 20:08:01 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2009-08-27 21:51:00 -0700 |
commit | 49237345d83e62fdb9eb8d50b13ad086636a04fa (patch) | |
tree | 224ca2d134177a09184c1440f4fceac13a10b627 | |
parent | 5511c66955d96019ee62ac334d73e4d2bcda178b (diff) | |
download | frameworks_base-49237345d83e62fdb9eb8d50b13ad086636a04fa.zip frameworks_base-49237345d83e62fdb9eb8d50b13ad086636a04fa.tar.gz frameworks_base-49237345d83e62fdb9eb8d50b13ad086636a04fa.tar.bz2 |
Add platform infrastructure for features.
This introduces a new mechanism to define features associated with
a platform, query the current device for the available features,
and enforce that apps requiring features that aren't available can't
be installed.
Also now allows uses-library to specify that a library is optional,
so the lack of such a library will not prevent the app from being
installed (but if it does exist it will be correctly linked into
the app).
Change-Id: I5b369b46cfa0b3d37c9e08fd14ef1098a978e67b
-rw-r--r-- | api/current.xml | 161 | ||||
-rw-r--r-- | core/java/android/app/ApplicationContext.java | 10 | ||||
-rwxr-xr-x | core/java/android/content/pm/ConfigurationInfo.java | 16 | ||||
-rwxr-xr-x | core/java/android/content/pm/FeatureInfo.aidl | 19 | ||||
-rw-r--r-- | core/java/android/content/pm/FeatureInfo.java | 101 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 7 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageInfo.java | 7 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 24 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 71 | ||||
-rw-r--r-- | core/res/res/values/attrs_manifest.xml | 8 | ||||
-rw-r--r-- | data/etc/android.hardware.camera.autofocus.xml | 21 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 109 | ||||
-rw-r--r-- | test-runner/android/test/mock/MockPackageManager.java | 6 | ||||
-rw-r--r-- | tools/aapt/Command.cpp | 7 |
14 files changed, 527 insertions, 40 deletions
diff --git a/api/current.xml b/api/current.xml index 96e1d2d..dcf0d84 100644 --- a/api/current.xml +++ b/api/current.xml @@ -37589,6 +37589,134 @@ > </field> </class> +<class name="FeatureInfo" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<constructor name="FeatureInfo" + type="android.content.pm.FeatureInfo" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="FeatureInfo" + type="android.content.pm.FeatureInfo" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="orig" type="android.content.pm.FeatureInfo"> +</parameter> +</constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getGlEsVersion" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="parcelableFlags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="FLAG_REQUIRED" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="GL_ES_VERSION_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="flags" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="name" + type="java.lang.String" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="reqGlEsVersion" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="InstrumentationInfo" extends="android.content.pm.PackageItemInfo" abstract="false" @@ -37850,6 +37978,17 @@ visibility="public" > </field> +<field name="reqFeatures" + type="android.content.pm.FeatureInfo[]" + transient="false" + volatile="false" + value="null" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="requestedPermissions" type="java.lang.String[]" transient="false" @@ -38719,6 +38858,17 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getSystemAvailableFeatures" + return="android.content.pm.FeatureInfo[]" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getSystemSharedLibraryNames" return="java.lang.String[]" abstract="true" @@ -122943,6 +123093,17 @@ <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException"> </exception> </method> +<method name="getSystemAvailableFeatures" + return="android.content.pm.FeatureInfo[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getSystemSharedLibraryNames" return="java.lang.String[]" abstract="false" diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 7c0d1d3..487cfda 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -40,6 +40,7 @@ import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; +import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; @@ -1623,6 +1624,15 @@ class ApplicationContext extends Context { } @Override + public FeatureInfo[] getSystemAvailableFeatures() { + try { + return mPM.getSystemAvailableFeatures(); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + + @Override public int checkPermission(String permName, String pkgName) { try { return mPM.checkPermission(permName, pkgName); diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java index fb7a47f..8edd436 100755 --- a/core/java/android/content/pm/ConfigurationInfo.java +++ b/core/java/android/content/pm/ConfigurationInfo.java @@ -22,9 +22,9 @@ import android.os.Parcelable; /** * Information you can retrieve about hardware configuration preferences * declared by an application. This corresponds to information collected from the - * AndroidManifest.xml's <uses-configuration> and the <uses-feature>tags. + * AndroidManifest.xml's <uses-configuration> and <uses-feature> tags. */ -public class ConfigurationInfo implements Parcelable { +public class ConfigurationInfo implements Parcelable { /** * The kind of touch screen attached to the device. * One of: {@link android.content.res.Configuration#TOUCHSCREEN_NOTOUCH}, @@ -92,13 +92,13 @@ public class ConfigurationInfo implements Parcelable { } public String toString() { - return "ApplicationHardwarePreferences{" + return "ConfigurationInfo{" + Integer.toHexString(System.identityHashCode(this)) - + ", touchscreen = " + reqTouchScreen + "}" - + ", inputMethod = " + reqKeyboardType + "}" - + ", navigation = " + reqNavigation + "}" - + ", reqInputFeatures = " + reqInputFeatures + "}" - + ", reqGlEsVersion = " + reqGlEsVersion + "}"; + + " touchscreen = " + reqTouchScreen + + " inputMethod = " + reqKeyboardType + + " navigation = " + reqNavigation + + " reqInputFeatures = " + reqInputFeatures + + " reqGlEsVersion = " + reqGlEsVersion + "}"; } public int describeContents() { diff --git a/core/java/android/content/pm/FeatureInfo.aidl b/core/java/android/content/pm/FeatureInfo.aidl new file mode 100755 index 0000000..d84a84c --- /dev/null +++ b/core/java/android/content/pm/FeatureInfo.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm; + +parcelable FeatureInfo; diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java new file mode 100644 index 0000000..57d61fd --- /dev/null +++ b/core/java/android/content/pm/FeatureInfo.java @@ -0,0 +1,101 @@ +package android.content.pm; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Parcelable.Creator; + +/** + * A single feature that can be requested by an application. This corresponds + * to information collected from the + * AndroidManifest.xml's <uses-feature> tag. + */ +public class FeatureInfo implements Parcelable { + /** + * The name of this feature, for example "android.hardware.camera". If + * this is null, then this is an OpenGL ES version feature as described + * in {@link #reqGlEsVersion}. + */ + public String name; + + /** + * Default value for {@link #reqGlEsVersion}; + */ + public static final int GL_ES_VERSION_UNDEFINED = 0; + + /** + * The GLES version used by an application. The upper order 16 bits represent the + * major version and the lower order 16 bits the minor version. Only valid + * if {@link #name} is null. + */ + public int reqGlEsVersion; + + /** + * Set on {@link #flags} if this feature has been required by the application. + */ + public static final int FLAG_REQUIRED = 0x0001; + + /** + * Additional flags. May be zero or more of {@link #FLAG_REQUIRED}. + */ + public int flags; + + public FeatureInfo() { + } + + public FeatureInfo(FeatureInfo orig) { + name = orig.name; + reqGlEsVersion = orig.reqGlEsVersion; + flags = orig.flags; + } + + public String toString() { + if (name != null) { + return "FeatureInfo{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + name + " fl=0x" + Integer.toHexString(flags) + "}"; + } else { + return "FeatureInfo{" + + Integer.toHexString(System.identityHashCode(this)) + + " glEsVers=" + getGlEsVersion() + + " fl=0x" + Integer.toHexString(flags) + "}"; + } + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeString(name); + dest.writeInt(reqGlEsVersion); + dest.writeInt(flags); + } + + public static final Creator<FeatureInfo> CREATOR = + new Creator<FeatureInfo>() { + public FeatureInfo createFromParcel(Parcel source) { + return new FeatureInfo(source); + } + public FeatureInfo[] newArray(int size) { + return new FeatureInfo[size]; + } + }; + + private FeatureInfo(Parcel source) { + name = source.readString(); + reqGlEsVersion = source.readInt(); + flags = source.readInt(); + } + + /** + * This method extracts the major and minor version of reqGLEsVersion attribute + * and returns it as a string. Say reqGlEsVersion value of 0x00010002 is returned + * as 1.2 + * @return String representation of the reqGlEsVersion attribute + */ + public String getGlEsVersion() { + int major = ((reqGlEsVersion & 0xffff0000) >> 16); + int minor = reqGlEsVersion & 0x0000ffff; + return String.valueOf(major)+"."+String.valueOf(minor); + } +} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 4fc4fb9..c322951 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.FeatureInfo; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageDataObserver; @@ -276,6 +277,12 @@ interface IPackageManager { */ String[] getSystemSharedLibraryNames(); + /** + * Get a list of features that are available on the + * system. + */ + FeatureInfo[] getSystemAvailableFeatures(); + void enterSafeMode(); boolean isSafeMode(); void systemReady(); diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d9326f2..a8ce889 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -127,6 +127,11 @@ public class PackageInfo implements Parcelable { */ public ConfigurationInfo[] configPreferences; + /** + * The features that this application has said it requires. + */ + public FeatureInfo[] reqFeatures; + public PackageInfo() { } @@ -162,6 +167,7 @@ public class PackageInfo implements Parcelable { dest.writeStringArray(requestedPermissions); dest.writeTypedArray(signatures, parcelableFlags); dest.writeTypedArray(configPreferences, parcelableFlags); + dest.writeTypedArray(reqFeatures, parcelableFlags); } public static final Parcelable.Creator<PackageInfo> CREATOR @@ -195,5 +201,6 @@ public class PackageInfo implements Parcelable { requestedPermissions = source.createStringArray(); signatures = source.createTypedArray(Signature.CREATOR); configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR); + reqFeatures = source.createTypedArray(FeatureInfo.CREATOR); } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index fca005c..825eb85 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -159,8 +159,10 @@ public abstract class PackageManager { /** * {@link PackageInfo} flag: return information about - * hardware preferences - * {@link PackageInfo#configPreferences} + * hardware preferences in + * {@link PackageInfo#configPreferences PackageInfo.configPreferences} and + * requested features in {@link PackageInfo#reqFeatures + * PackageInfo.reqFeatures}. */ public static final int GET_CONFIGURATIONS = 0x00004000; @@ -400,6 +402,14 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16; /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package uses a feature that is not available. + * @hide + */ + public static final int INSTALL_FAILED_MISSING_FEATURE = -17; + + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected @@ -980,6 +990,16 @@ public abstract class PackageManager { public abstract String[] getSystemSharedLibraryNames(); /** + * Get a list of features that are available on the + * system. + * + * @return An array of FeatureInfo classes describing the features + * that are available on the system, or null if there are none(!!). + * + */ + public abstract FeatureInfo[] getSystemAvailableFeatures(); + + /** * Determine the best action to perform for a given Intent. This is how * {@link Intent#resolveActivity} finds an activity if a class has not * been explicitly specified. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 96c9486..4399df4 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -184,9 +184,12 @@ public class PackageParser { int N = p.configPreferences.size(); if (N > 0) { pi.configPreferences = new ConfigurationInfo[N]; - for (int i=0; i<N; i++) { - pi.configPreferences[i] = p.configPreferences.get(i); - } + p.configPreferences.toArray(pi.configPreferences); + } + N = p.reqFeatures != null ? p.reqFeatures.size() : 0; + if (N > 0) { + pi.reqFeatures = new FeatureInfo[N]; + p.reqFeatures.toArray(pi.reqFeatures); } } if ((flags&PackageManager.GET_ACTIVITIES) != 0) { @@ -760,14 +763,32 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); } else if (tagName.equals("uses-feature")) { - ConfigurationInfo cPref = new ConfigurationInfo(); + FeatureInfo fi = new FeatureInfo(); sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesFeature); - cPref.reqGlEsVersion = sa.getInt( - com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, - ConfigurationInfo.GL_ES_VERSION_UNDEFINED); + fi.name = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestUsesFeature_name); + if (fi.name == null) { + fi.reqGlEsVersion = sa.getInt( + com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, + FeatureInfo.GL_ES_VERSION_UNDEFINED); + } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestUsesFeature_required, + true)) { + fi.flags |= FeatureInfo.FLAG_REQUIRED; + } sa.recycle(); - pkg.configPreferences.add(cPref); + if (pkg.reqFeatures == null) { + pkg.reqFeatures = new ArrayList<FeatureInfo>(); + } + pkg.reqFeatures.add(fi); + + if (fi.name == null) { + ConfigurationInfo cPref = new ConfigurationInfo(); + cPref.reqGlEsVersion = fi.reqGlEsVersion; + pkg.configPreferences.add(cPref); + } XmlUtils.skipCurrentTag(parser); @@ -946,11 +967,6 @@ public class PackageParser { } } - if (pkg.usesLibraries.size() > 0) { - pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()]; - pkg.usesLibraries.toArray(pkg.usesLibraryFiles); - } - if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { @@ -1436,11 +1452,28 @@ public class PackageParser { String lname = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, + true); sa.recycle(); - if (lname != null && !owner.usesLibraries.contains(lname)) { - owner.usesLibraries.add(lname.intern()); + if (lname != null) { + if (req) { + if (owner.usesLibraries == null) { + owner.usesLibraries = new ArrayList<String>(); + } + if (!owner.usesLibraries.contains(lname)) { + owner.usesLibraries.add(lname.intern()); + } + } else { + if (owner.usesOptionalLibraries == null) { + owner.usesOptionalLibraries = new ArrayList<String>(); + } + if (!owner.usesOptionalLibraries.contains(lname)) { + owner.usesOptionalLibraries.add(lname.intern()); + } + } } XmlUtils.skipCurrentTag(parser); @@ -2418,7 +2451,8 @@ public class PackageParser { public ArrayList<String> protectedBroadcasts; - public final ArrayList<String> usesLibraries = new ArrayList<String>(); + public ArrayList<String> usesLibraries = null; + public ArrayList<String> usesOptionalLibraries = null; public String[] usesLibraryFiles = null; // We store the application meta-data independently to avoid multiple unwanted references @@ -2466,6 +2500,11 @@ public class PackageParser { public final ArrayList<ConfigurationInfo> configPreferences = new ArrayList<ConfigurationInfo>(); + /* + * Applications requested features + */ + public ArrayList<FeatureInfo> reqFeatures = null; + public Package(String _name) { packageName = _name; applicationInfo.packageName = _name; diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index d1079d0..ce421db 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -832,6 +832,14 @@ <declare-styleable name="AndroidManifestUsesLibrary" parent="AndroidManifestApplication"> <!-- Required name of the library you use. --> <attr name="name" /> + <!-- Specify whether this library is required for the application. + The default is true, meaning the application requires the + library, and does not want to be installed on devices that + don't support it. If you set this to false, then this will + allow the application to be installed even if the library + doesn't exist, and you will need to check for its presence + dynamically at runtime. --> + <attr name="required" /> </declare-styleable> <!-- The <code>supports-screens</code> specifies the screen dimensions an diff --git a/data/etc/android.hardware.camera.autofocus.xml b/data/etc/android.hardware.camera.autofocus.xml new file mode 100644 index 0000000..d6e2b90 --- /dev/null +++ b/data/etc/android.hardware.camera.autofocus.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard set of features for an auto-focus camera. --> +<permissions> + <feature name="android.hardware.camera" /> + <feature name="android.hardware.camera.autofocus" /> +</permissions> diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 2f4d716..8ec6ec3 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -35,6 +35,7 @@ import android.content.IntentSender.SendIntentException; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; +import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; @@ -88,6 +89,7 @@ import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; @@ -221,6 +223,14 @@ class PackageManagerService extends IPackageManager.Stub { // etc/permissions.xml file. final HashMap<String, String> mSharedLibraries = new HashMap<String, String>(); + // Temporary for building the final shared libraries for an .apk. + String[] mTmpSharedLibraries = null; + + // These are the features this devices supports that were read from the + // etc/permissions.xml file. + final HashMap<String, FeatureInfo> mAvailableFeatures = + new HashMap<String, FeatureInfo>(); + // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); @@ -671,7 +681,21 @@ class PackageManagerService extends IPackageManager.Stub { + parser.getPositionDescription()); } else { Log.i(TAG, "Got library " + lname + " in " + lfile); - this.mSharedLibraries.put(lname, lfile); + mSharedLibraries.put(lname, lfile); + } + XmlUtils.skipCurrentTag(parser); + continue; + + } else if ("feature".equals(name)) { + String fname = parser.getAttributeValue(null, "name"); + if (fname == null) { + Log.w(TAG, "<feature> without name at " + + parser.getPositionDescription()); + } else { + Log.i(TAG, "Got feature " + fname); + FeatureInfo fi = new FeatureInfo(); + fi.name = fname; + mAvailableFeatures.put(fname, fi); } XmlUtils.skipCurrentTag(parser); continue; @@ -1001,12 +1025,30 @@ class PackageManagerService extends IPackageManager.Stub { Set<String> libSet; synchronized (mPackages) { libSet = mSharedLibraries.keySet(); + int size = libSet.size(); + if (size > 0) { + String[] libs = new String[size]; + libSet.toArray(libs); + return libs; + } } - int size = libSet.size(); - if (size > 0) { - String[] libs = new String[size]; - libSet.toArray(libs); - return libs; + return null; + } + + public FeatureInfo[] getSystemAvailableFeatures() { + Collection<FeatureInfo> featSet; + synchronized (mPackages) { + featSet = mAvailableFeatures.values(); + int size = featSet.size(); + if (size > 0) { + FeatureInfo[] features = new FeatureInfo[size+1]; + featSet.toArray(features); + FeatureInfo fi = new FeatureInfo(); + fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version", + FeatureInfo.GL_ES_VERSION_UNDEFINED); + features[size] = fi; + return features; + } } return null; } @@ -2065,17 +2107,62 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { // Check all shared libraries and map to their actual file path. - if (pkg.usesLibraryFiles != null) { - for (int i=0; i<pkg.usesLibraryFiles.length; i++) { - String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]); + if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { + if (mTmpSharedLibraries == null || + mTmpSharedLibraries.length < mSharedLibraries.size()) { + mTmpSharedLibraries = new String[mSharedLibraries.size()]; + } + int num = 0; + int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0; + for (int i=0; i<N; i++) { + String file = mSharedLibraries.get(pkg.usesLibraries.get(i)); if (file == null) { Log.e(TAG, "Package " + pkg.packageName + " requires unavailable shared library " - + pkg.usesLibraryFiles[i] + "; ignoring!"); + + pkg.usesLibraries.get(i) + "; failing!"); mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; return null; } - pkg.usesLibraryFiles[i] = file; + mTmpSharedLibraries[num] = file; + num++; + } + N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0; + for (int i=0; i<N; i++) { + String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i)); + if (file == null) { + Log.w(TAG, "Package " + pkg.packageName + + " desires unavailable shared library " + + pkg.usesOptionalLibraries.get(i) + "; ignoring!"); + } else { + mTmpSharedLibraries[num] = file; + num++; + } + } + if (num > 0) { + pkg.usesLibraryFiles = new String[num]; + System.arraycopy(mTmpSharedLibraries, 0, + pkg.usesLibraryFiles, 0, num); + } + + if (pkg.reqFeatures != null) { + N = pkg.reqFeatures.size(); + for (int i=0; i<N; i++) { + FeatureInfo fi = pkg.reqFeatures.get(i); + if ((fi.flags&FeatureInfo.FLAG_REQUIRED) == 0) { + // Don't care. + continue; + } + + if (fi.name != null) { + if (mAvailableFeatures.get(fi.name) == null) { + Log.e(TAG, "Package " + pkg.packageName + + " requires unavailable feature " + + fi.name + "; failing!"); + mLastScanError = PackageManager.INSTALL_FAILED_MISSING_FEATURE; + return null; + } + } + } } } diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index 4a50c5d..beb9044 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -22,6 +22,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.FeatureInfo; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstallObserver; @@ -424,6 +425,11 @@ public class MockPackageManager extends PackageManager { } @Override + public FeatureInfo[] getSystemAvailableFeatures() { + throw new UnsupportedOperationException(); + } + + @Override public boolean isSafeMode() { throw new UnsupportedOperationException(); } diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index f4afd7f..790b474 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -730,8 +730,6 @@ int doDump(Bundle* bundle) } else if (tag == "uses-permission") { String8 name = getAttribute(tree, NAME_ATTR, &error); if (error == "") { - int opt = getIntegerAttribute(tree, - REQUIRED_ATTR, NULL, 1); if (name == "android.permission.CAMERA") { hasCameraPermission = true; } @@ -772,7 +770,10 @@ int doDump(Bundle* bundle) fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string()); goto bail; } - printf("uses-library:'%s'\n", libraryName.string()); + int req = getIntegerAttribute(tree, + REQUIRED_ATTR, NULL, 1); + printf("uses-library%s:'%s'\n", + req ? "" : "-not-required", libraryName.string()); } else if (tag == "receiver") { withinReceiver = true; receiverName = getAttribute(tree, NAME_ATTR, &error); |