Merge "Optimize IntentResolver to reduce lookup time by 50%."

This commit is contained in:
Jeff Brown
2011-01-28 17:55:36 -08:00
committed by Android (Google) Code Review
4 changed files with 126 additions and 39 deletions

View File

@@ -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;

View File

@@ -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;
}

View 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();
}
}
}

View File

@@ -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));