diff options
10 files changed, 501 insertions, 81 deletions
| diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java index ead6c25989ce..fc5853353ce6 100644 --- a/core/java/android/content/ComponentName.java +++ b/core/java/android/content/ComponentName.java @@ -396,4 +396,14 @@ public final class ComponentName implements Parcelable, Cloneable, Comparable<Co          mPackage = pkg;          mClass = in.readString();      } + +    /** +     * Interface for classes associated with a component name. +     * @hide +     */ +    @FunctionalInterface +    public interface WithComponentName { +        /** Return the associated component name. */ +        ComponentName getComponentName(); +    }  } diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 433d14f7b453..083c0c9736f9 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -29,6 +29,7 @@ import java.util.Collections;  import java.util.List;  import java.util.Set;  import java.util.function.Function; +import java.util.function.Predicate;  import java.util.stream.Stream;  /** @@ -84,6 +85,17 @@ public class CollectionUtils {          return emptyIfNull(result);      } +    /** Add all elements matching {@code predicate} in {@code source} to {@code dest}. */ +    public static <T> void addIf(@Nullable List<T> source, @NonNull Collection<? super T> dest, +            @Nullable Predicate<? super T> predicate) { +        for (int i = 0; i < size(source); i++) { +            final T item = source.get(i); +            if (predicate.test(item)) { +                dest.add(item); +            } +        } +    } +      /**       * Returns a list of items resulting from applying the given function to each element of the       * provided list. diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index e85b782facb2..7fd83bc6c8b9 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -16,18 +16,25 @@  package com.android.internal.util; +import android.annotation.Nullable;  import android.app.AppOpsManager; +import android.content.ComponentName;  import android.content.Context;  import android.content.pm.PackageManager;  import android.os.Binder;  import android.os.Handler; +import android.text.TextUtils;  import android.util.Slog;  import java.io.PrintWriter;  import java.io.StringWriter; +import java.util.Objects; +import java.util.function.Predicate;  /**   * Helper functions for dumping the state of system services. + * Test: + atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java   */  public final class DumpUtils {      private static final String TAG = "DumpUtils"; @@ -153,4 +160,99 @@ public final class DumpUtils {              PrintWriter pw) {          return checkDumpPermission(context, tag, pw) && checkUsageStatsPermission(context, tag, pw);      } + +    /** +     * Return whether a package name is considered to be part of the platform. +     * @hide +     */ +    public static boolean isPlatformPackage(@Nullable String packageName) { +        return (packageName != null) +                && (packageName.equals("android") +                    || packageName.startsWith("android.") +                    || packageName.startsWith("com.android.")); +    } + +    /** +     * Return whether a package name is considered to be part of the platform. +     * @hide +     */ +    public static boolean isPlatformPackage(@Nullable ComponentName cname) { +        return (cname != null) && isPlatformPackage(cname.getPackageName()); +    } + +    /** +     * Return whether a package name is considered to be part of the platform. +     * @hide +     */ +    public static boolean isPlatformPackage(@Nullable ComponentName.WithComponentName wcn) { +        return (wcn != null) && isPlatformPackage(wcn.getComponentName()); +    } + +    /** +     * Return whether a package name is NOT considered to be part of the platform. +     * @hide +     */ +    public static boolean isNonPlatformPackage(@Nullable String packageName) { +        return (packageName != null) && !isPlatformPackage(packageName); +    } + +    /** +     * Return whether a package name is NOT considered to be part of the platform. +     * @hide +     */ +    public static boolean isNonPlatformPackage(@Nullable ComponentName cname) { +        return (cname != null) && isNonPlatformPackage(cname.getPackageName()); +    } + +    /** +     * Return whether a package name is NOT considered to be part of the platform. +     * @hide +     */ +    public static boolean isNonPlatformPackage(@Nullable ComponentName.WithComponentName wcn) { +        return (wcn != null) && !isPlatformPackage(wcn.getComponentName()); +    } + +    /** +     * Used for dumping providers and services. Return a predicate for a given filter string. +     * @hide +     */ +    public static <TRec extends ComponentName.WithComponentName> Predicate<TRec> filterRecord( +            @Nullable String filterString) { + +        if (TextUtils.isEmpty(filterString)) { +            return rec -> false; +        } + +        // Dump all? +        if ("all".equals(filterString)) { +            return Objects::nonNull; +        } + +        // Dump all platform? +        if ("all-platform".equals(filterString)) { +            return DumpUtils::isPlatformPackage; +        } + +        // Dump all non-platform? +        if ("all-non-platform".equals(filterString)) { +            return DumpUtils::isNonPlatformPackage; +        } + +        // Is the filter a component name? If so, do an exact match. +        final ComponentName filterCname = ComponentName.unflattenFromString(filterString); +        if (filterCname != null) { +            // Do exact component name check. +            return rec -> (rec != null) && filterCname.equals(rec.getComponentName()); +        } + +        // Otherwise, do a partial match against the component name. +        // Also if the filter is a hex-decimal string, do the object ID match too. +        final int id = ParseUtils.parseIntWithBase(filterString, 16, -1); +        return rec -> { +            final ComponentName cn = rec.getComponentName(); +            return ((id != -1) && (System.identityHashCode(rec) == id)) +                    || cn.flattenToString().toLowerCase().contains(filterString.toLowerCase()); +        }; +    }  } + diff --git a/core/java/com/android/internal/util/ParseUtils.java b/core/java/com/android/internal/util/ParseUtils.java new file mode 100644 index 000000000000..a591f4aa41fc --- /dev/null +++ b/core/java/com/android/internal/util/ParseUtils.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 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 com.android.internal.util; + +import android.annotation.Nullable; + +/** + * Various numeric -> strings conversion. + * + * Test: + atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java + */ +public final class ParseUtils { +    private ParseUtils() { +    } + +    /** Parse a value as a base-10 integer. */ +    public static int parseInt(@Nullable String value, int defValue) { +        return parseIntWithBase(value, 10, defValue); +    } + +    /** Parse a value as an integer of a given base. */ +    public static int parseIntWithBase(@Nullable String value, int base, int defValue) { +        if (value == null) { +            return defValue; +        } +        try { +            return Integer.parseInt(value, base); +        } catch (NumberFormatException e) { +            return defValue; +        } +    } + +    /** Parse a value as a base-10 long. */ +    public static long parseLong(@Nullable String value, long defValue) { +        return parseLongWithBase(value, 10, defValue); +    } + +    /** Parse a value as a long of a given base. */ +    public static long parseLongWithBase(@Nullable String value, int base, long defValue) { +        if (value == null) { +            return defValue; +        } +        try { +            return Long.parseLong(value, base); +        } catch (NumberFormatException e) { +            return defValue; +        } +    } + +    /** Parse a value as a float. */ +    public static float parseFloat(@Nullable String value, float defValue) { +        if (value == null) { +            return defValue; +        } +        try { +            return Float.parseFloat(value); +        } catch (NumberFormatException e) { +            return defValue; +        } +    } + +    /** Parse a value as a double. */ +    public static double parseDouble(@Nullable String value, double defValue) { +        if (value == null) { +            return defValue; +        } +        try { +            return Double.parseDouble(value); +        } catch (NumberFormatException e) { +            return defValue; +        } +    } + +    /** Parse a value as a boolean. */ +    public static boolean parseBoolean(@Nullable String value, boolean defValue) { +        if ("true".equals(value)) { +            return true; +        } +        if ("false".equals(value)) { +            return false; +        } +        return parseInt(value, defValue ? 1 : 0) != 0; +    } +} diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java new file mode 100644 index 000000000000..45b19bccff88 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 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 com.android.internal.util; + +import static com.android.internal.util.DumpUtils.filterRecord; +import static com.android.internal.util.DumpUtils.isNonPlatformPackage; +import static com.android.internal.util.DumpUtils.isPlatformPackage; + +import android.content.ComponentName; + +import junit.framework.TestCase; + +/** + * Run with: + atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java + */ +public class DumpUtilsTest extends TestCase { + +    private static ComponentName cn(String componentName) { +        if (componentName == null) { +            return null; +        } +        return ComponentName.unflattenFromString(componentName); +    } + +    private static ComponentName.WithComponentName wcn(String componentName) { +        if (componentName == null) { +            return null; +        } +        return () -> cn(componentName); +    } + +    public void testIsPlatformPackage() { +        assertTrue(isPlatformPackage("android")); +        assertTrue(isPlatformPackage("android.abc")); +        assertTrue(isPlatformPackage("com.android.abc")); + +        assertFalse(isPlatformPackage((String) null)); +        assertFalse(isPlatformPackage("com.google")); + +        assertTrue(isPlatformPackage(cn("android/abc"))); +        assertTrue(isPlatformPackage(cn("android.abc/abc"))); +        assertTrue(isPlatformPackage(cn("com.android.def/abc"))); + +        assertFalse(isPlatformPackage(cn(null))); +        assertFalse(isPlatformPackage(cn("com.google.def/abc"))); + +        assertTrue(isPlatformPackage(wcn("android/abc"))); +        assertTrue(isPlatformPackage(wcn("android.abc/abc"))); +        assertTrue(isPlatformPackage(wcn("com.android.def/abc"))); + +        assertFalse(isPlatformPackage(wcn(null))); +        assertFalse(isPlatformPackage(wcn("com.google.def/abc"))); +    } + +    public void testIsNonPlatformPackage() { +        assertFalse(isNonPlatformPackage("android")); +        assertFalse(isNonPlatformPackage("android.abc")); +        assertFalse(isNonPlatformPackage("com.android.abc")); + +        assertFalse(isNonPlatformPackage((String) null)); +        assertTrue(isNonPlatformPackage("com.google")); + +        assertFalse(isNonPlatformPackage(cn("android/abc"))); +        assertFalse(isNonPlatformPackage(cn("android.abc/abc"))); +        assertFalse(isNonPlatformPackage(cn("com.android.def/abc"))); + +        assertFalse(isNonPlatformPackage(cn(null))); +        assertTrue(isNonPlatformPackage(cn("com.google.def/abc"))); + +        assertFalse(isNonPlatformPackage(wcn("android/abc"))); +        assertFalse(isNonPlatformPackage(wcn("android.abc/abc"))); +        assertFalse(isNonPlatformPackage(wcn("com.android.def/abc"))); + +        assertFalse(isNonPlatformPackage(wcn(null))); +        assertTrue(isNonPlatformPackage(wcn("com.google.def/abc"))); +    } + +    public void testFilterRecord() { +        assertFalse(filterRecord(null).test(wcn("com.google.p/abc"))); +        assertFalse(filterRecord(null).test(wcn("com.android.p/abc"))); + +        assertTrue(filterRecord("all").test(wcn("com.google.p/abc"))); +        assertTrue(filterRecord("all").test(wcn("com.android.p/abc"))); +        assertFalse(filterRecord("all").test(wcn(null))); + +        assertFalse(filterRecord("all-platform").test(wcn("com.google.p/abc"))); +        assertTrue(filterRecord("all-platform").test(wcn("com.android.p/abc"))); +        assertFalse(filterRecord("all-platform").test(wcn(null))); + +        assertTrue(filterRecord("all-non-platform").test(wcn("com.google.p/abc"))); +        assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc"))); +        assertFalse(filterRecord("all-non-platform").test(wcn(null))); + +        // Partial string match. +        assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc"))); +        assertFalse(filterRecord("abc").test(wcn("com.google.p/.def"))); +        assertTrue(filterRecord("com").test(wcn("com.google.p/.xyz"))); + +        // Full component name match. +        assertTrue(filterRecord("com.google/com.google.abc").test(wcn("com.google/.abc"))); +        assertFalse(filterRecord("com.google/com.google.abc").test(wcn("com.google/.abc.def"))); + + +        // Hex ID match +        ComponentName.WithComponentName component = wcn("com.google/.abc"); + +        assertTrue(filterRecord( +                Integer.toHexString(System.identityHashCode(component))).test(component)); +        // Same component name, but different ID, no match. +        assertFalse(filterRecord( +                Integer.toHexString(System.identityHashCode(component))).test( +                        wcn("com.google/.abc"))); +    } +} diff --git a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java new file mode 100644 index 000000000000..f00c48c96b5d --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 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 com.android.internal.util; + +import junit.framework.TestCase; + +/** + * Run with: + atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java + */ +public class ParseUtilsTest extends TestCase { +    public void testParseInt() { +        assertEquals(1, ParseUtils.parseInt(null, 1)); +        assertEquals(1, ParseUtils.parseInt("", 1)); +        assertEquals(1, ParseUtils.parseInt("1x", 1)); +        assertEquals(2, ParseUtils.parseInt("2", 1)); + +        assertEquals(2, ParseUtils.parseInt("+2", 1)); +        assertEquals(-2, ParseUtils.parseInt("-2", 1)); +    } + +    public void testParseIntWithBase() { +        assertEquals(1, ParseUtils.parseIntWithBase(null, 10, 1)); +        assertEquals(1, ParseUtils.parseIntWithBase("", 10, 1)); +        assertEquals(1, ParseUtils.parseIntWithBase("1x", 10, 1)); +        assertEquals(2, ParseUtils.parseIntWithBase("2", 10, 1)); +        assertEquals(10, ParseUtils.parseIntWithBase("10", 10, 1)); +        assertEquals(3, ParseUtils.parseIntWithBase("10", 3, 1)); + +        assertEquals(3, ParseUtils.parseIntWithBase("+10", 3, 1)); +        assertEquals(-3, ParseUtils.parseIntWithBase("-10", 3, 1)); +    } + +    public void testParseLong() { +        assertEquals(1L, ParseUtils.parseLong(null, 1)); +        assertEquals(1L, ParseUtils.parseLong("", 1)); +        assertEquals(1L, ParseUtils.parseLong("1x", 1)); +        assertEquals(2L, ParseUtils.parseLong("2", 1)); +    } + +    public void testParseLongWithBase() { +        assertEquals(1L, ParseUtils.parseLongWithBase(null, 10, 1)); +        assertEquals(1L, ParseUtils.parseLongWithBase("", 10, 1)); +        assertEquals(1L, ParseUtils.parseLongWithBase("1x", 10, 1)); +        assertEquals(2L, ParseUtils.parseLongWithBase("2", 10, 1)); +        assertEquals(10L, ParseUtils.parseLongWithBase("10", 10, 1)); +        assertEquals(3L, ParseUtils.parseLongWithBase("10", 3, 1)); + +        assertEquals(3L, ParseUtils.parseLongWithBase("+10", 3, 1)); +        assertEquals(-3L, ParseUtils.parseLongWithBase("-10", 3, 1)); + +        assertEquals(10_000_000_000L, ParseUtils.parseLongWithBase("+10000000000", 10, 1)); +        assertEquals(-10_000_000_000L, ParseUtils.parseLongWithBase("-10000000000", 10, 1)); + +        assertEquals(10_000_000_000L, ParseUtils.parseLongWithBase(null, 10, 10_000_000_000L)); +    } + +    public void testParseFloat() { +        assertEquals(0.5f, ParseUtils.parseFloat(null, 0.5f)); +        assertEquals(0.5f, ParseUtils.parseFloat("", 0.5f)); +        assertEquals(0.5f, ParseUtils.parseFloat("1x", 0.5f)); +        assertEquals(1.5f, ParseUtils.parseFloat("1.5", 0.5f)); +    } + +    public void testParseDouble() { +        assertEquals(0.5, ParseUtils.parseDouble(null, 0.5)); +        assertEquals(0.5, ParseUtils.parseDouble("", 0.5)); +        assertEquals(0.5, ParseUtils.parseDouble("1x", 0.5)); +        assertEquals(1.5, ParseUtils.parseDouble("1.5", 0.5)); +    } + +    public void testParseBoolean() { +        assertEquals(false, ParseUtils.parseBoolean(null, false)); +        assertEquals(true, ParseUtils.parseBoolean(null, true)); + +        assertEquals(false, ParseUtils.parseBoolean("", false)); +        assertEquals(true, ParseUtils.parseBoolean("", true)); + +        assertEquals(true, ParseUtils.parseBoolean("true", false)); +        assertEquals(true, ParseUtils.parseBoolean("true", true)); + +        assertEquals(false, ParseUtils.parseBoolean("false", false)); +        assertEquals(false, ParseUtils.parseBoolean("false", true)); + +        assertEquals(true, ParseUtils.parseBoolean("1", false)); +        assertEquals(true, ParseUtils.parseBoolean("1", true)); + +        assertEquals(false, ParseUtils.parseBoolean("0", false)); +        assertEquals(false, ParseUtils.parseBoolean("0", true)); +    } +} diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index fc047bc6e832..228171ff65f8 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -24,15 +24,19 @@ import java.io.IOException;  import java.io.PrintWriter;  import java.io.StringWriter;  import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator;  import java.util.HashSet;  import java.util.Iterator;  import java.util.List;  import java.util.Set; +import java.util.function.Predicate;  import android.app.ActivityThread;  import android.app.AppOpsManager;  import android.app.NotificationManager;  import android.app.ServiceStartArgs; +import android.content.ComponentName.WithComponentName;  import android.content.IIntentSender;  import android.content.IntentSender;  import android.content.pm.ParceledListSlice; @@ -55,6 +59,8 @@ import com.android.internal.messages.nano.SystemMessageProto;  import com.android.internal.notification.SystemNotificationChannels;  import com.android.internal.os.BatteryStatsImpl;  import com.android.internal.os.TransferPipe; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DumpUtils;  import com.android.internal.util.FastPrintWriter;  import com.android.server.AppStateTracker;  import com.android.server.LocalServices; @@ -4063,57 +4069,26 @@ public final class ActiveServices {       *  - the first arg isn't the flattened component name of an existing service:       *    dump all services whose component contains the first arg as a substring       */ -    protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, String[] args, -            int opti, boolean dumpAll) { -        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); +    protected boolean dumpService(FileDescriptor fd, PrintWriter pw, final String name, +            String[] args, int opti, boolean dumpAll) { +        final ArrayList<ServiceRecord> services = new ArrayList<>(); + +        final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name);          synchronized (mAm) {              int[] users = mAm.mUserController.getUsers(); -            if ("all".equals(name)) { -                for (int user : users) { -                    ServiceMap smap = mServiceMap.get(user); -                    if (smap == null) { -                        continue; -                    } -                    ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByName; -                    for (int i=0; i<alls.size(); i++) { -                        ServiceRecord r1 = alls.valueAt(i); -                        services.add(r1); -                    } -                } -            } else { -                ComponentName componentName = name != null -                        ? ComponentName.unflattenFromString(name) : null; -                int objectId = 0; -                if (componentName == null) { -                    // Not a '/' separated full component name; maybe an object ID? -                    try { -                        objectId = Integer.parseInt(name, 16); -                        name = null; -                        componentName = null; -                    } catch (RuntimeException e) { -                    } + +            for (int user : users) { +                ServiceMap smap = mServiceMap.get(user); +                if (smap == null) { +                    continue;                  } +                ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByName; +                for (int i=0; i<alls.size(); i++) { +                    ServiceRecord r1 = alls.valueAt(i); -                for (int user : users) { -                    ServiceMap smap = mServiceMap.get(user); -                    if (smap == null) { -                        continue; -                    } -                    ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByName; -                    for (int i=0; i<alls.size(); i++) { -                        ServiceRecord r1 = alls.valueAt(i); -                        if (componentName != null) { -                            if (r1.name.equals(componentName)) { -                                services.add(r1); -                            } -                        } else if (name != null) { -                            if (r1.name.flattenToString().contains(name)) { -                                services.add(r1); -                            } -                        } else if (System.identityHashCode(r1) == objectId) { -                            services.add(r1); -                        } +                    if (filter.test(r1)) { +                        services.add(r1);                      }                  }              } @@ -4123,6 +4098,9 @@ public final class ActiveServices {              return false;          } +        // Sort by component name. +        services.sort(Comparator.comparing(WithComponentName::getComponentName)); +          boolean needSep = false;          for (int i=0; i<services.size(); i++) {              if (needSep) { diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index 7b9b6595d7cf..cd39bcd03d36 100644 --- a/services/core/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java @@ -32,7 +32,7 @@ import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.HashMap; -final class ContentProviderRecord { +final class ContentProviderRecord implements ComponentName.WithComponentName {      final ActivityManagerService service;      public final ProviderInfo info;      final int uid; @@ -260,4 +260,8 @@ final class ContentProviderRecord {              }          }      } + +    public ComponentName getComponentName() { +        return name; +    }  } diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java index 8a905f8c045e..2f520027c1ca 100644 --- a/services/core/java/com/android/server/am/ProviderMap.java +++ b/services/core/java/com/android/server/am/ProviderMap.java @@ -17,22 +17,28 @@  package com.android.server.am;  import android.content.ComponentName; +import android.content.ComponentName.WithComponentName;  import android.os.Binder;  import android.os.RemoteException;  import android.os.UserHandle;  import android.util.Slog;  import android.util.SparseArray;  import com.android.internal.os.TransferPipe; +import com.android.internal.util.CollectionUtils; +import com.android.internal.util.DumpUtils;  import java.io.FileDescriptor;  import java.io.IOException;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator;  import java.util.HashMap;  import java.util.Iterator;  import java.util.Map;  import java.util.Set; +import java.util.function.Predicate;  /**   * Keeps track of content providers by authority (name) and class. It separates the mapping by @@ -325,7 +331,9 @@ public final class ProviderMap {      private ArrayList<ContentProviderRecord> getProvidersForName(String name) {          ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>(); -        ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); +        final ArrayList<ContentProviderRecord> ret = new ArrayList<>(); + +        final Predicate<ContentProviderRecord> filter = DumpUtils.filterRecord(name);          synchronized (mAm) {              allProviders.addAll(mSingletonByClass.values()); @@ -333,39 +341,11 @@ public final class ProviderMap {                  allProviders.addAll(mProvidersByClassPerUser.valueAt(i).values());              } -            if ("all".equals(name)) { -                providers.addAll(allProviders); -            } else { -                ComponentName componentName = name != null -                        ? ComponentName.unflattenFromString(name) : null; -                int objectId = 0; -                if (componentName == null) { -                    // Not a '/' separated full component name; maybe an object ID? -                    try { -                        objectId = Integer.parseInt(name, 16); -                        name = null; -                        componentName = null; -                    } catch (RuntimeException e) { -                    } -                } - -                for (int i=0; i<allProviders.size(); i++) { -                    ContentProviderRecord r1 = allProviders.get(i); -                    if (componentName != null) { -                        if (r1.name.equals(componentName)) { -                            providers.add(r1); -                        } -                    } else if (name != null) { -                        if (r1.name.flattenToString().contains(name)) { -                            providers.add(r1); -                        } -                    } else if (System.identityHashCode(r1) == objectId) { -                        providers.add(r1); -                    } -                } -            } +            CollectionUtils.addIf(allProviders, ret, filter);          } -        return providers; +        // Sort by component name. +        ret.sort(Comparator.comparing(WithComponentName::getComponentName)); +        return ret;      }      protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args, diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 8a174edbefa3..32887e400903 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -56,7 +56,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA  /**   * A running application service.   */ -final class ServiceRecord extends Binder { +final class ServiceRecord extends Binder implements ComponentName.WithComponentName {      private static final String TAG = TAG_WITH_CLASS_NAME ? "ServiceRecord" : TAG_AM;      // Maximum number of delivery attempts before giving up. @@ -757,4 +757,8 @@ final class ServiceRecord extends Binder {              .append(' ').append(shortName).append('}');          return stringName = sb.toString();      } + +    public ComponentName getComponentName() { +        return name; +    }  } |