diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 40 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 13 | ||||
| -rw-r--r-- | core/java/android/content/IntentFilter.java | 148 | ||||
| -rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 6 | ||||
| -rw-r--r-- | core/java/android/content/pm/IntentFilterVerificationInfo.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/content/pm/IntentFilterVerificationInfo.java | 224 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 181 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageParser.java | 18 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageUserState.java | 9 | ||||
| -rw-r--r-- | core/java/android/content/pm/ResolveInfo.java | 8 | ||||
| -rw-r--r-- | core/java/android/provider/Settings.java | 2 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/ResolverActivity.java | 31 |
12 files changed, 683 insertions, 16 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 6d74905..6ec5457 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -36,6 +36,7 @@ import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; +import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; import android.content.pm.ManifestDigest; import android.content.pm.PackageInfo; @@ -1309,6 +1310,45 @@ final class ApplicationPackageManager extends PackageManager { } @Override + public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) { + try { + mPM.verifyIntentFilter(id, verificationCode, outFailedDomains); + } catch (RemoteException e) { + // Should never happen! + } + } + + @Override + public int getIntentVerificationStatus(String packageName, int userId) { + try { + return mPM.getIntentVerificationStatus(packageName, userId); + } catch (RemoteException e) { + // Should never happen! + return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + } + } + + @Override + public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { + try { + return mPM.updateIntentVerificationStatus(packageName, status, userId); + } catch (RemoteException e) { + // Should never happen! + return false; + } + } + + @Override + public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) { + try { + return mPM.getIntentFilterVerifications(packageName); + } catch (RemoteException e) { + // Should never happen! + return null; + } + } + + @Override public void setInstallerPackageName(String targetPackage, String installerPackageName) { try { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 030b770..7a99a79 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1911,6 +1911,19 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED"; /** + * Broadcast Action: Sent to the system intent filter verifier when an intent filter + * needs to be verified. The data contains the filter data hosts to be verified against. + * <p class="note"> + * This is a protected intent that can only be sent by the system. + * </p> + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"; + + /** * Broadcast Action: Resources for a set of packages (which were * previously unavailable) are currently * available since the media on which they exist is available. diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 1240a23..590d791 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -16,10 +16,12 @@ package android.content; +import android.content.pm.PackageParser; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; +import android.text.TextUtils; import android.util.AndroidException; import android.util.Log; import android.util.Printer; @@ -150,6 +152,7 @@ public class IntentFilter implements Parcelable { private static final String CAT_STR = "cat"; private static final String NAME_STR = "name"; private static final String ACTION_STR = "action"; + private static final String AUTO_VERIFY_STR = "autoVerify"; /** * The filter {@link #setPriority} value at which system high-priority @@ -247,6 +250,19 @@ public class IntentFilter implements Parcelable { */ public static final int NO_MATCH_CATEGORY = -4; + /** + * HTTP scheme. + * + * @see #addDataScheme(String) + */ + public static final String SCHEME_HTTP = "http"; + /** + * HTTPS scheme. + * + * @see #addDataScheme(String) + */ + public static final String SCHEME_HTTPS = "https"; + private int mPriority; private final ArrayList<String> mActions; private ArrayList<String> mCategories = null; @@ -257,6 +273,13 @@ public class IntentFilter implements Parcelable { private ArrayList<String> mDataTypes = null; private boolean mHasPartialTypes = false; + private static final int STATE_VERIFY_AUTO = 0x00000001; + private static final int STATE_NEED_VERIFY = 0x00000010; + private static final int STATE_NEED_VERIFY_CHECKED = 0x00000100; + private static final int STATE_VERIFIED = 0x00001000; + + private int mVerifyState; + // These functions are the start of more optimized code for managing // the string sets... not yet implemented. @@ -326,7 +349,7 @@ public class IntentFilter implements Parcelable { public MalformedMimeTypeException(String name) { super(name); } - }; + } /** * Create a new IntentFilter instance with a specified action and MIME @@ -421,6 +444,7 @@ public class IntentFilter implements Parcelable { mDataPaths = new ArrayList<PatternMatcher>(o.mDataPaths); } mHasPartialTypes = o.mHasPartialTypes; + mVerifyState = o.mVerifyState; } /** @@ -452,6 +476,94 @@ public class IntentFilter implements Parcelable { } /** + * Set whether this filter will needs to be automatically verified against its data URIs or not. + * The default is false. + * + * The verification would need to happen only and only if the Intent action is + * {@link android.content.Intent#ACTION_VIEW} and the Intent category is + * {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent data scheme + * is "http" or "https". + * + * True means that the filter will need to use its data URIs to be verified. + * + * @param autoVerify The new autoVerify value. + * + * @see #getAutoVerify() + * @see #addAction(String) + * @see #getAction(int) + * @see #addCategory(String) + * @see #getCategory(int) + * @see #addDataScheme(String) + * @see #getDataScheme(int) + * + * @hide + */ + public final void setAutoVerify(boolean autoVerify) { + mVerifyState &= ~STATE_VERIFY_AUTO; + if (autoVerify) mVerifyState |= STATE_VERIFY_AUTO; + } + + /** + * Return if this filter will needs to be automatically verified again its data URIs or not. + * + * @return True if the filter will needs to be automatically verified. False otherwise. + * + * @see #setAutoVerify(boolean) + * + * @hide + */ + public final boolean getAutoVerify() { + return ((mVerifyState & STATE_VERIFY_AUTO) == 1); + } + + /** + * Return if this filter needs to be automatically verified again its data URIs or not. + * + * @return True if the filter needs to be automatically verified. False otherwise. + * + * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and + * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent + * data scheme is "http" or "https". + * + * @see #setAutoVerify(boolean) + * + * @hide + */ + public final boolean needsVerification() { + return hasAction(Intent.ACTION_VIEW) && + hasCategory(Intent.CATEGORY_BROWSABLE) && + (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS)) && + getAutoVerify(); + } + + /** + * Return if this filter has been verified + * + * @return true if the filter has been verified or if autoVerify is false. + * + * @hide + */ + public final boolean isVerified() { + if ((mVerifyState & STATE_NEED_VERIFY_CHECKED) == STATE_NEED_VERIFY_CHECKED) { + return ((mVerifyState & STATE_NEED_VERIFY) == STATE_NEED_VERIFY); + } + return false; + } + + /** + * Set if this filter has been verified + * + * @param verified true if this filter has been verified. False otherwise. + * + * @hide + */ + public void setVerified(boolean verified) { + mVerifyState |= STATE_NEED_VERIFY_CHECKED; + mVerifyState &= ~STATE_VERIFIED; + if (verified) mVerifyState |= STATE_VERIFIED; + } + + /** * Add a new Intent action to match against. If any actions are included * in the filter, then an Intent's action must be one of those values for * it to match. If no actions are included, the Intent action is ignored. @@ -1333,6 +1445,7 @@ public class IntentFilter implements Parcelable { * Write the contents of the IntentFilter as an XML stream. */ public void writeToXml(XmlSerializer serializer) throws IOException { + serializer.attribute(null, AUTO_VERIFY_STR, Boolean.toString(getAutoVerify())); int N = countActions(); for (int i=0; i<N; i++) { serializer.startTag(null, ACTION_STR); @@ -1407,6 +1520,9 @@ public class IntentFilter implements Parcelable { public void readFromXml(XmlPullParser parser) throws XmlPullParserException, IOException { + String autoVerify = parser.getAttributeValue(null, AUTO_VERIFY_STR); + setAutoVerify(TextUtils.isEmpty(autoVerify) ? false : Boolean.getBoolean(autoVerify)); + int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -1548,6 +1664,11 @@ public class IntentFilter implements Parcelable { sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes); du.println(sb.toString()); } + { + sb.setLength(0); + sb.append(prefix); sb.append("AutoVerify="); sb.append(getAutoVerify()); + du.println(sb.toString()); + } } public static final Parcelable.Creator<IntentFilter> CREATOR @@ -1614,6 +1735,7 @@ public class IntentFilter implements Parcelable { } dest.writeInt(mPriority); dest.writeInt(mHasPartialTypes ? 1 : 0); + dest.writeInt(getAutoVerify() ? 1 : 0); } /** @@ -1680,6 +1802,7 @@ public class IntentFilter implements Parcelable { } mPriority = source.readInt(); mHasPartialTypes = source.readInt() > 0; + setAutoVerify(source.readInt() > 0); } private final boolean findMimeType(String type) { @@ -1724,4 +1847,27 @@ public class IntentFilter implements Parcelable { return false; } + + /** + * @hide + */ + public ArrayList<String> getHostsList() { + ArrayList<String> result = new ArrayList<>(); + Iterator<IntentFilter.AuthorityEntry> it = authoritiesIterator(); + if (it != null) { + while (it.hasNext()) { + IntentFilter.AuthorityEntry entry = it.next(); + result.add(entry.getHost()); + } + } + return result; + } + + /** + * @hide + */ + public String[] getHosts() { + ArrayList<String> list = getHostsList(); + return list.toArray(new String[list.size()]); + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c6d97f1..66b0d1a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -31,6 +31,7 @@ import android.content.pm.IPackageDeleteObserver2; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; +import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.KeySet; import android.content.pm.PackageInfo; @@ -436,6 +437,11 @@ interface IPackageManager { void verifyPendingInstall(int id, int verificationCode); void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay); + void verifyIntentFilter(int id, int verificationCode, in List<String> outFailedDomains); + int getIntentVerificationStatus(String packageName, int userId); + boolean updateIntentVerificationStatus(String packageName, int status, int userId); + List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName); + VerifierDeviceIdentity getVerifierDeviceIdentity(); boolean isFirstBoot(); diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.aidl b/core/java/android/content/pm/IntentFilterVerificationInfo.aidl new file mode 100644 index 0000000..00220e5 --- /dev/null +++ b/core/java/android/content/pm/IntentFilterVerificationInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015 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 IntentFilterVerificationInfo; diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java new file mode 100644 index 0000000..60cb4a8 --- /dev/null +++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2015 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; + +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.Log; +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; + +/** + * The {@link com.android.server.pm.PackageManagerService} maintains some + * {@link IntentFilterVerificationInfo}s for each domain / package / class name per user. + * + * @hide + */ +public final class IntentFilterVerificationInfo implements Parcelable { + private static final String TAG = IntentFilterVerificationInfo.class.getName(); + + private static final String TAG_DOMAIN = "domain"; + private static final String ATTR_DOMAIN_NAME = "name"; + private static final String ATTR_PACKAGE_NAME = "packageName"; + private static final String ATTR_STATUS = "status"; + + private String[] mDomains; + private String mPackageName; + private int mMainStatus; + + public IntentFilterVerificationInfo() { + mPackageName = null; + mDomains = new String[0]; + mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + } + + public IntentFilterVerificationInfo(String packageName, String[] domains) { + mPackageName = packageName; + mDomains = domains; + mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + } + + public IntentFilterVerificationInfo(XmlPullParser parser) + throws IOException, XmlPullParserException { + readFromXml(parser); + } + + public IntentFilterVerificationInfo(Parcel source) { + readFromParcel(source); + } + + public String[] getDomains() { + return mDomains; + } + + public String getPackageName() { + return mPackageName; + } + + public int getStatus() { + return mMainStatus; + } + + public void setStatus(int s) { + if (s >= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED && + s <= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { + mMainStatus = s; + } else { + Log.w(TAG, "Trying to set a non supported status: " + s); + } + } + + public String getDomainsString() { + StringBuilder sb = new StringBuilder(); + for (String str : mDomains) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append(str); + } + return sb.toString(); + } + + String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) { + String value = parser.getAttributeValue(null, attribute); + if (value == null) { + String msg = "Missing element under " + TAG +": " + attribute + " at " + + parser.getPositionDescription(); + Log.w(TAG, msg); + return defaultValue; + } else { + return value; + } + } + + int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) { + String value = parser.getAttributeValue(null, attribute); + if (TextUtils.isEmpty(value)) { + String msg = "Missing element under " + TAG +": " + attribute + " at " + + parser.getPositionDescription(); + Log.w(TAG, msg); + return defaultValue; + } else { + return Integer.parseInt(value); + } + } + + public void readFromXml(XmlPullParser parser) throws XmlPullParserException, + IOException { + mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null); + if (mPackageName == null) { + Log.e(TAG, "Package name cannot be null!"); + } + int status = getIntFromXml(parser, ATTR_STATUS, -1); + if (status == -1) { + Log.e(TAG, "Unknown status value: " + status); + } + mMainStatus = status; + + ArrayList<String> list = new ArrayList<>(); + 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; + } + + String tagName = parser.getName(); + if (tagName.equals(TAG_DOMAIN)) { + String name = getStringFromXml(parser, ATTR_DOMAIN_NAME, null); + if (!TextUtils.isEmpty(name)) { + if (list == null) { + list = new ArrayList<>(); + } + list.add(name); + } + } else { + Log.w(TAG, "Unknown tag parsing IntentFilter: " + tagName); + } + XmlUtils.skipCurrentTag(parser); + } + + mDomains = list.toArray(new String[list.size()]); + } + + public void writeToXml(XmlSerializer serializer) throws IOException { + serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName); + serializer.attribute(null, ATTR_STATUS, String.valueOf(mMainStatus)); + for (String str : mDomains) { + serializer.startTag(null, TAG_DOMAIN); + serializer.attribute(null, ATTR_DOMAIN_NAME, str); + serializer.endTag(null, TAG_DOMAIN); + } + } + + public String getStatusString() { + return getStatusStringFromValue(mMainStatus); + } + + public static String getStatusStringFromValue(int val) { + switch (val) { + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK : return "ask"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS : return "always"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER : return "never"; + default: + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : return "undefined"; + } + } + + @Override + public int describeContents() { + return 0; + } + + private void readFromParcel(Parcel source) { + mPackageName = source.readString(); + mMainStatus = source.readInt(); + mDomains = source.readStringArray(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPackageName); + dest.writeInt(mMainStatus); + dest.writeStringArray(mDomains); + } + + public static final Creator<IntentFilterVerificationInfo> CREATOR = + new Creator<IntentFilterVerificationInfo>() { + public IntentFilterVerificationInfo createFromParcel(Parcel source) { + return new IntentFilterVerificationInfo(source); + } + public IntentFilterVerificationInfo[] newArray(int size) { + return new IntentFilterVerificationInfo[size]; + } + }; + +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f0d1da9..46d6ffb3 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -969,6 +969,60 @@ public abstract class PackageManager { public static final int VERIFICATION_REJECT = -1; /** + * Used as the {@code verificationCode} argument for + * {@link PackageManager#verifyIntentFilter} to indicate that the calling + * IntentFilter Verifier confirms that the IntentFilter is verified. + * + * @hide + */ + public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; + + /** + * Used as the {@code verificationCode} argument for + * {@link PackageManager#verifyIntentFilter} to indicate that the calling + * IntentFilter Verifier confirms that the IntentFilter is NOT verified. + * + * @hide + */ + public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; + + /** + * Internal status code to indicate that an IntentFilter verification result is not specified. + * + * @hide + */ + public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0; + + /** + * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus} + * to indicate that the User will always be prompted the Intent Disambiguation Dialog if there + * are two or more Intent resolved for the IntentFilter's domain(s). + * + * @hide + */ + public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1; + + /** + * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus} + * to indicate that the User will never be prompted the Intent Disambiguation Dialog if there + * are two or more resolution of the Intent. The default App for the domain(s) specified in the + * IntentFilter will also ALWAYS be used. + * + * @hide + */ + public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2; + + /** + * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus} + * to indicate that the User may be prompted the Intent Disambiguation Dialog if there + * are two or more Intent resolved. The default App for the domain(s) specified in the + * IntentFilter will also NEVER be presented to the User. + * + * @hide + */ + public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3; + + /** * Can be used as the {@code millisecondsToDelay} argument for * {@link PackageManager#extendVerificationTimeout}. This is the * maximum time {@code PackageManager} waits for the verification @@ -1680,8 +1734,52 @@ public abstract class PackageManager { = "android.content.pm.extra.VERIFICATION_VERSION_CODE"; /** - * The action used to request that the user approve a grant permissions - * request from the application. + * Extra field name for the ID of a intent filter pending verification. Passed to + * an intent filter verifier and is used to call back to + * {@link PackageManager#verifyIntentFilter(int, int)} + * + * @hide + */ + public static final String EXTRA_INTENT_FILTER_VERIFICATION_ID + = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_ID"; + + /** + * Extra field name for the scheme used for an intent filter pending verification. Passed to + * an intent filter verifier and is used to construct the URI to verify against. + * + * Usually this is "https" + * + * @hide + */ + public static final String EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME + = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_URI_SCHEME"; + + /** + * Extra field name for the host names to be used for an intent filter pending verification. + * Passed to an intent filter verifier and is used to construct the URI to verify the + * intent filter. + * + * This is a space delimited list of hosts. + * + * @hide + */ + public static final String EXTRA_INTENT_FILTER_VERIFICATION_HOSTS + = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_HOSTS"; + + /** + * Extra field name for the package name to be used for an intent filter pending verification. + * Passed to an intent filter verifier and is used to check the verification responses coming + * from the hosts. Each host response will need to include the package name of APK containing + * the intent filter. + * + * @hide + */ + public static final String EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME + = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_PACKAGE_NAME"; + + /** + * The action used to request that the user approve a permission request + * from the application. * * @hide */ @@ -3461,6 +3559,85 @@ public abstract class PackageManager { int verificationCodeAtTimeout, long millisecondsToDelay); /** + * Allows a package listening to the + * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION intent filter verification + * broadcast} to respond to the package manager. The response must include + * the {@code verificationCode} which is one of + * {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} or + * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}. + * + * @param verificationId pending package identifier as passed via the + * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra. + * @param verificationCode either {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} + * or {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}. + * @param outFailedDomains a list of failed domains if the verificationCode is + * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}, otherwise null; + * @throws SecurityException if the caller does not have the + * INTENT_FILTER_VERIFICATION_AGENT permission. + * + * @hide + */ + public abstract void verifyIntentFilter(int verificationId, int verificationCode, + List<String> outFailedDomains); + + /** + * Get the status of a Domain Verification Result for an IntentFilter. This is + * related to the {@link android.content.IntentFilter#setAutoVerify(boolean)} and + * {@link android.content.IntentFilter#getAutoVerify()} + * + * This is used by the ResolverActivity to change the status depending on what the User select + * in the Disambiguation Dialog and also used by the Settings App for changing the default App + * for a domain. + * + * @param packageName The package name of the Activity associated with the IntentFilter. + * @param userId The user id. + * + * @return The status to set to. This can be + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} or + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS} or + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER} or + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED} + * + * @hide + */ + public abstract int getIntentVerificationStatus(String packageName, int userId); + + /** + * Allow to change the status of a Intent Verification status for all IntentFilter of an App. + * This is related to the {@link android.content.IntentFilter#setAutoVerify(boolean)} and + * {@link android.content.IntentFilter#getAutoVerify()} + * + * This is used by the ResolverActivity to change the status depending on what the User select + * in the Disambiguation Dialog and also used by the Settings App for changing the default App + * for a domain. + * + * @param packageName The package name of the Activity associated with the IntentFilter. + * @param status The status to set to. This can be + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} or + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS} or + * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER} + * @param userId The user id. + * + * @return true if the status has been set. False otherwise. + * + * @hide + */ + public abstract boolean updateIntentVerificationStatus(String packageName, int status, + int userId); + + /** + * Get the list of IntentFilterVerificationInfo for a specific package and User. + * + * @param packageName the package name. When this parameter is set to a non null value, + * the results will be filtered by the package name provided. + * Otherwise, there will be no filtering and it will return a list + * corresponding for all packages for the provided userId. + * @return a list of IntentFilterVerificationInfo for a specific package and User. + */ + public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications( + String packageName); + + /** * Change the installer associated with a given package. There are limitations * on how the installer package can be changed; in particular: * <ul> diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 212cf6d..e20057d 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3149,7 +3149,7 @@ public class PackageParser { if (parser.getName().equals("intent-filter")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); - if (!parseIntent(res, parser, attrs, true, intent, outError)) { + if (!parseIntent(res, parser, attrs, true, true, intent, outError)) { return null; } if (intent.countActions() == 0) { @@ -3161,7 +3161,7 @@ public class PackageParser { } } else if (!receiver && parser.getName().equals("preferred")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); - if (!parseIntent(res, parser, attrs, false, intent, outError)) { + if (!parseIntent(res, parser, attrs, false, false, intent, outError)) { return null; } if (intent.countActions() == 0) { @@ -3341,7 +3341,7 @@ public class PackageParser { if (parser.getName().equals("intent-filter")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); - if (!parseIntent(res, parser, attrs, true, intent, outError)) { + if (!parseIntent(res, parser, attrs, true, true, intent, outError)) { return null; } if (intent.countActions() == 0) { @@ -3521,7 +3521,7 @@ public class PackageParser { if (parser.getName().equals("intent-filter")) { ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); - if (!parseIntent(res, parser, attrs, true, intent, outError)) { + if (!parseIntent(res, parser, attrs, true, false, intent, outError)) { return false; } outInfo.intents.add(intent); @@ -3780,7 +3780,7 @@ public class PackageParser { if (parser.getName().equals("intent-filter")) { ServiceIntentInfo intent = new ServiceIntentInfo(s); - if (!parseIntent(res, parser, attrs, true, intent, outError)) { + if (!parseIntent(res, parser, attrs, true, false, intent, outError)) { return null; } @@ -3981,7 +3981,7 @@ public class PackageParser { = "http://schemas.android.com/apk/res/android"; private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, - boolean allowGlobs, IntentInfo outInfo, String[] outError) + boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, @@ -4006,6 +4006,12 @@ public class PackageParser { outInfo.banner = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); + if (allowAutoVerify) { + outInfo.setAutoVerify(sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify, + false)); + } + sa.recycle(); int outerDepth = parser.getDepth(); diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index a9c7be3..92b8055 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -37,10 +37,14 @@ public class PackageUserState { public ArraySet<String> disabledComponents; public ArraySet<String> enabledComponents; + public int domainVerificationStatus; + public PackageUserState() { installed = true; hidden = false; enabled = COMPONENT_ENABLED_STATE_DEFAULT; + domainVerificationStatus = + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; } public PackageUserState(PackageUserState o) { @@ -51,9 +55,10 @@ public class PackageUserState { hidden = o.hidden; lastDisableAppCaller = o.lastDisableAppCaller; disabledComponents = o.disabledComponents != null - ? new ArraySet<String>(o.disabledComponents) : null; + ? new ArraySet<>(o.disabledComponents) : null; enabledComponents = o.enabledComponents != null - ? new ArraySet<String>(o.enabledComponents) : null; + ? new ArraySet<>(o.enabledComponents) : null; blockUninstall = o.blockUninstall; + domainVerificationStatus = o.domainVerificationStatus; } } diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index fe3aec9..7b141f0 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -143,6 +143,11 @@ public class ResolveInfo implements Parcelable { */ public boolean system; + /** + * @hide Does the associated IntentFilter needs verification ? + */ + public boolean filterNeedsVerification; + private ComponentInfo getComponentInfo() { if (activityInfo != null) return activityInfo; if (serviceInfo != null) return serviceInfo; @@ -283,6 +288,7 @@ public class ResolveInfo implements Parcelable { resolvePackageName = orig.resolvePackageName; system = orig.system; targetUserId = orig.targetUserId; + filterNeedsVerification = orig.filterNeedsVerification; } public String toString() { @@ -344,6 +350,7 @@ public class ResolveInfo implements Parcelable { dest.writeInt(targetUserId); dest.writeInt(system ? 1 : 0); dest.writeInt(noResourceId ? 1 : 0); + dest.writeInt(filterNeedsVerification ? 1 : 0); } public static final Creator<ResolveInfo> CREATOR @@ -389,6 +396,7 @@ public class ResolveInfo implements Parcelable { targetUserId = source.readInt(); system = source.readInt() != 0; noResourceId = source.readInt() != 0; + filterNeedsVerification = source.readInt() != 0; } public static class DisplayNameComparator diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fb51528..8e5d245 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6097,7 +6097,7 @@ public final class Settings { public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible"; /** - * Run package verificaiton on apps installed through ADB/ADT/USB + * Run package verification on apps installed through ADB/ADT/USB * 1 = perform package verification on ADB installs (default) * 0 = bypass package verification on ADB installs * @hide diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 3ceea9d..6b35f3f 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -604,9 +604,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) { // Build a reasonable intent filter, based on what matched. IntentFilter filter = new IntentFilter(); + String action = intent.getAction(); - if (intent.getAction() != null) { - filter.addAction(intent.getAction()); + if (action != null) { + filter.addAction(action); } Set<String> categories = intent.getCategories(); if (categories != null) { @@ -688,8 +689,30 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic if (r.match > bestMatch) bestMatch = r.match; } if (alwaysCheck) { - getPackageManager().addPreferredActivity(filter, bestMatch, set, - intent.getComponent()); + PackageManager pm = getPackageManager(); + + // Set the preferred Activity + pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent()); + + // Update Domain Verification status + int userId = getUserId(); + ComponentName cn = intent.getComponent(); + String packageName = cn.getPackageName(); + String dataScheme = (data != null) ? data.getScheme() : null; + + boolean isHttpOrHttps = (dataScheme != null) && + (dataScheme.equals(IntentFilter.SCHEME_HTTP) || + dataScheme.equals(IntentFilter.SCHEME_HTTPS)); + + boolean isViewAction = (action != null) && action.equals(Intent.ACTION_VIEW); + boolean hasCategoryBrowsable = (categories != null) && + categories.contains(Intent.CATEGORY_BROWSABLE); + + if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) { + pm.updateIntentVerificationStatus(packageName, + PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, + userId); + } } else { try { AppGlobals.getPackageManager().setLastChosenActivity(intent, |
