Merge "Optimize IntentResolver to reduce lookup time by 50%."
This commit is contained in:
@@ -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<String>();
|
||||
}
|
||||
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<String>();
|
||||
int i;
|
||||
for (i=0; i<N; i++) {
|
||||
mCategories.add(in.readString());
|
||||
mCategories.add(in.readString().intern());
|
||||
}
|
||||
} else {
|
||||
mCategories = null;
|
||||
|
||||
@@ -461,7 +461,7 @@ public class IntentFilter implements Parcelable {
|
||||
* @return True if the action is explicitly mentioned in the filter.
|
||||
*/
|
||||
public final boolean hasAction(String action) {
|
||||
return mActions.contains(action);
|
||||
return action != null && mActions.contains(action);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -470,14 +470,10 @@ public class IntentFilter implements Parcelable {
|
||||
*
|
||||
* @param action The desired action to look for.
|
||||
*
|
||||
* @return True if the action is listed in the filter or the filter does
|
||||
* not specify any actions.
|
||||
* @return True if the action is listed in the filter.
|
||||
*/
|
||||
public final boolean matchAction(String action) {
|
||||
if (action == null || mActions == null || mActions.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
return mActions.contains(action);
|
||||
return hasAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -818,9 +814,9 @@ public class IntentFilter implements Parcelable {
|
||||
if (mDataPaths == null) {
|
||||
return false;
|
||||
}
|
||||
Iterator<PatternMatcher> 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<AuthorityEntry> 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<String> 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<String> 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;
|
||||
}
|
||||
|
||||
78
core/java/android/util/FastImmutableArraySet.java
Normal file
78
core/java/android/util/FastImmutableArraySet.java
Normal file
@@ -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<T> extends AbstractSet<T> {
|
||||
FastIterator<T> mIterator;
|
||||
T[] mContents;
|
||||
|
||||
public FastImmutableArraySet(T[] contents) {
|
||||
mContents = contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
FastIterator<T> it = mIterator;
|
||||
if (it == null) {
|
||||
it = new FastIterator<T>(mContents);
|
||||
mIterator = it;
|
||||
} else {
|
||||
it.mIndex = 0;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mContents.length;
|
||||
}
|
||||
|
||||
private static final class FastIterator<T> implements Iterator<T> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<F extends IntentFilter, R extends Object> {
|
||||
final boolean debug = localLOGV ||
|
||||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
|
||||
|
||||
FastImmutableArraySet<String> 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<F extends IntentFilter, R extends Object> {
|
||||
if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
|
||||
}
|
||||
|
||||
FastImmutableArraySet<String> 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<F extends IntentFilter, R extends Object> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void buildResolveList(Intent intent, boolean debug, boolean defaultOnly,
|
||||
private static FastImmutableArraySet<String> getFastIntentCategories(Intent intent) {
|
||||
final Set<String> categories = intent.getCategories();
|
||||
if (categories == null) {
|
||||
return null;
|
||||
}
|
||||
return new FastImmutableArraySet<String>(categories.toArray(new String[categories.size()]));
|
||||
}
|
||||
|
||||
private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
|
||||
boolean debug, boolean defaultOnly,
|
||||
String resolvedType, String scheme, List<F> src, List<R> dest) {
|
||||
Set<String> 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<F extends IntentFilter, R extends Object> {
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user