diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 6e3663e341d52..e7b96e7f40986 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2794,7 +2794,7 @@ public class Intent implements Parcelable, Cloneable { * @param action The Intent action, such as ACTION_VIEW. */ public Intent(String action) { - mAction = action; + setAction(action); } /** @@ -2814,7 +2814,7 @@ public class Intent implements Parcelable, Cloneable { * @param uri The Intent data URI. */ public Intent(String action, Uri uri) { - mAction = action; + setAction(action); mData = uri; } @@ -2863,7 +2863,7 @@ public class Intent implements Parcelable, Cloneable { */ public Intent(String action, Uri uri, Context packageContext, Class cls) { - mAction = action; + setAction(action); mData = uri; mComponent = new ComponentName(packageContext, cls); } @@ -2985,7 +2985,7 @@ public class Intent implements Parcelable, Cloneable { // action if (uri.startsWith("action=", i)) { - intent.mAction = value; + intent.setAction(value); } // categories @@ -4061,7 +4061,7 @@ public class Intent implements Parcelable, Cloneable { * @see #getAction */ public Intent setAction(String action) { - mAction = action; + mAction = action != null ? action.intern() : null; return this; } @@ -4165,7 +4165,7 @@ public class Intent implements Parcelable, Cloneable { if (mCategories == null) { mCategories = new HashSet(); } - mCategories.add(category); + mCategories.add(category.intern()); return this; } @@ -5678,7 +5678,7 @@ public class Intent implements Parcelable, Cloneable { } public void readFromParcel(Parcel in) { - mAction = in.readString(); + setAction(in.readString()); mData = Uri.CREATOR.createFromParcel(in); mType = in.readString(); mFlags = in.readInt(); @@ -5694,7 +5694,7 @@ public class Intent implements Parcelable, Cloneable { mCategories = new HashSet(); int i; for (i=0; i i = mDataPaths.iterator(); - while (i.hasNext()) { - final PatternMatcher pe = i.next(); + final int numDataPaths = mDataPaths.size(); + for (int i = 0; i < numDataPaths; i++) { + final PatternMatcher pe = mDataPaths.get(i); if (pe.match(data)) { return true; } @@ -849,9 +845,9 @@ public class IntentFilter implements Parcelable { if (mDataAuthorities == null) { return NO_MATCH_DATA; } - Iterator i = mDataAuthorities.iterator(); - while (i.hasNext()) { - final AuthorityEntry ae = i.next(); + final int numDataAuthorities = mDataAuthorities.size(); + for (int i = 0; i < numDataAuthorities; i++) { + final AuthorityEntry ae = mDataAuthorities.get(i); int match = ae.match(data); if (match >= 0) { return match; @@ -1098,7 +1094,7 @@ public class IntentFilter implements Parcelable { */ public final int match(String action, String type, String scheme, Uri data, Set categories, String logTag) { - if (action != null && !matchAction(action)) { + if (!matchAction(action)) { if (Config.LOGV) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; @@ -1119,11 +1115,11 @@ public class IntentFilter implements Parcelable { return dataMatch; } - String categoryMatch = matchCategories(categories); - if (categoryMatch != null) { - if (Config.LOGV) Log.v( - logTag, "No matching category " - + categoryMatch + " for " + this); + String categoryMismatch = matchCategories(categories); + if (categoryMismatch != null) { + if (Config.LOGV) { + Log.v(logTag, "No matching category " + categoryMismatch + " for " + this); + } return NO_MATCH_CATEGORY; } @@ -1469,9 +1465,9 @@ public class IntentFilter implements Parcelable { if (typeLength == slashpos+2 && type.charAt(slashpos+1) == '*') { // Need to look through all types for one that matches // our base... - final Iterator it = t.iterator(); - while (it.hasNext()) { - String v = it.next(); + final int numTypes = t.size(); + for (int i = 0; i < numTypes; i++) { + final String v = t.get(i); if (type.regionMatches(0, v, 0, slashpos+1)) { return true; } diff --git a/core/java/android/util/FastImmutableArraySet.java b/core/java/android/util/FastImmutableArraySet.java new file mode 100644 index 0000000000000..4175c6057ecf7 --- /dev/null +++ b/core/java/android/util/FastImmutableArraySet.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 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.util; + +import java.util.AbstractSet; +import java.util.Iterator; + +/** + * A fast immutable set wrapper for an array that is optimized for non-concurrent iteration. + * The same iterator instance is reused each time to avoid creating lots of garbage. + * Iterating over an array in this fashion is 2.5x faster than iterating over a {@link HashSet} + * so it is worth copying the contents of the set to an array when iterating over it + * hundreds of times. + * @hide + */ +public final class FastImmutableArraySet extends AbstractSet { + FastIterator mIterator; + T[] mContents; + + public FastImmutableArraySet(T[] contents) { + mContents = contents; + } + + @Override + public Iterator iterator() { + FastIterator it = mIterator; + if (it == null) { + it = new FastIterator(mContents); + mIterator = it; + } else { + it.mIndex = 0; + } + return it; + } + + @Override + public int size() { + return mContents.length; + } + + private static final class FastIterator implements Iterator { + private final T[] mContents; + int mIndex; + + public FastIterator(T[] contents) { + mContents = contents; + } + + @Override + public boolean hasNext() { + return mIndex != mContents.length; + } + + @Override + public T next() { + return mContents[mIndex++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index a8b28403ee1a6..e9ee12ca2b8be 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import android.net.Uri; +import android.util.FastImmutableArraySet; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -207,10 +209,11 @@ public class IntentResolver { final boolean debug = localLOGV || ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); + FastImmutableArraySet categories = getFastIntentCategories(intent); final String scheme = intent.getScheme(); int N = listCut.size(); for (int i = 0; i < N; ++i) { - buildResolveList(intent, debug, defaultOnly, + buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, listCut.get(i), resultList); } sortResults(resultList); @@ -286,20 +289,21 @@ public class IntentResolver { if (debug) Slog.v(TAG, "Action list: " + firstTypeCut); } + FastImmutableArraySet categories = getFastIntentCategories(intent); if (firstTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, + buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, firstTypeCut, finalList); } if (secondTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, + buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, secondTypeCut, finalList); } if (thirdTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, + buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, thirdTypeCut, finalList); } if (schemeCut != null) { - buildResolveList(intent, debug, defaultOnly, + buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, schemeCut, finalList); } sortResults(finalList); @@ -478,9 +482,19 @@ public class IntentResolver { return false; } - private void buildResolveList(Intent intent, boolean debug, boolean defaultOnly, + private static FastImmutableArraySet getFastIntentCategories(Intent intent) { + final Set categories = intent.getCategories(); + if (categories == null) { + return null; + } + return new FastImmutableArraySet(categories.toArray(new String[categories.size()])); + } + + private void buildResolveList(Intent intent, FastImmutableArraySet categories, + boolean debug, boolean defaultOnly, String resolvedType, String scheme, List src, List dest) { - Set categories = intent.getCategories(); + final String action = intent.getAction(); + final Uri data = intent.getData(); final int N = src != null ? src.size() : 0; boolean hasNonDefaults = false; @@ -498,8 +512,7 @@ public class IntentResolver { continue; } - match = filter.match( - intent.getAction(), resolvedType, scheme, intent.getData(), categories, TAG); + match = filter.match(action, resolvedType, scheme, data, categories, TAG); if (match >= 0) { if (debug) Slog.v(TAG, " Filter matched! match=0x" + Integer.toHexString(match));