Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c09d9982 authored by Grace Cheng's avatar Grace Cheng Committed by Android (Google) Code Review
Browse files

Merge changes from topic "revert-33879976-packagetags-PVKUIEFLTJ" into main

* changes:
  Revert "Adds unit tests for PackageTagsMap."
  Revert "Adds PackageTagsMap."
parents 92cdcf75 c8bcceca
Loading
Loading
Loading
Loading
+0 −22
Original line number Diff line number Diff line
@@ -430,28 +430,6 @@ package android.os {
    method public boolean shouldBypassCache(@NonNull Q);
  }

  @FlaggedApi("android.location.flags.change_get_adas_allowlist_from_hidden_to_system") public final class PackageTagsMap implements android.os.Parcelable {
    method public boolean contains(@NonNull String, @Nullable String);
    method public boolean containsAll(@NonNull android.os.PackageTagsMap);
    method public boolean containsPackage(@NonNull String);
    method public boolean containsPackageWithAllTags(@NonNull String);
    method public int describeContents();
    method @NonNull public java.util.Set<java.lang.String> getPackages();
    method public boolean isEmpty();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.os.PackageTagsMap> CREATOR;
  }

  public static final class PackageTagsMap.Builder {
    ctor public PackageTagsMap.Builder();
    ctor public PackageTagsMap.Builder(int);
    method @NonNull public android.os.PackageTagsMap.Builder add(@NonNull String);
    method @NonNull public android.os.PackageTagsMap.Builder add(@NonNull String, @Nullable String);
    method @NonNull public android.os.PackageTagsMap.Builder addAll(@NonNull android.os.PackageTagsMap);
    method @NonNull public android.os.PackageTagsMap.Builder addAll(@NonNull java.util.Map<java.lang.String,? extends java.util.Set<java.lang.String>>);
    method @NonNull public android.os.PackageTagsMap build();
  }

  public class Process {
    method public static final int toSdkSandboxUid(int);
    field public static final int NFC_UID = 1027; // 0x403
+0 −22
Original line number Diff line number Diff line
@@ -2555,28 +2555,6 @@ package android.os {
    ctor public NewUserResponse(@Nullable android.os.UserHandle, int);
  }

  @FlaggedApi("android.location.flags.change_get_adas_allowlist_from_hidden_to_system") public final class PackageTagsMap implements android.os.Parcelable {
    method public boolean contains(@NonNull String, @Nullable String);
    method public boolean containsAll(@NonNull android.os.PackageTagsMap);
    method public boolean containsPackage(@NonNull String);
    method public boolean containsPackageWithAllTags(@NonNull String);
    method public int describeContents();
    method @NonNull public java.util.Set<java.lang.String> getPackages();
    method public boolean isEmpty();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.os.PackageTagsMap> CREATOR;
  }

  public static final class PackageTagsMap.Builder {
    ctor public PackageTagsMap.Builder();
    ctor public PackageTagsMap.Builder(int);
    method @NonNull public android.os.PackageTagsMap.Builder add(@NonNull String);
    method @NonNull public android.os.PackageTagsMap.Builder add(@NonNull String, @Nullable String);
    method @NonNull public android.os.PackageTagsMap.Builder addAll(@NonNull android.os.PackageTagsMap);
    method @NonNull public android.os.PackageTagsMap.Builder addAll(@NonNull java.util.Map<java.lang.String,? extends java.util.Set<java.lang.String>>);
    method @NonNull public android.os.PackageTagsMap build();
  }

  public final class Parcel {
    method public boolean allowSquashing();
    method public int getFlags();
+0 −19
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.os;

parcelable PackageTagsMap;
+0 −435
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.os;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.location.flags.Flags;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.internal.annotations.Immutable;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * A list of packages and associated attribution tags that supports easy membership checks. Supports
 * "wildcard" attribution tags (ie, matching any attribution tag under a package) in additional to
 * standard checks.
 *
 * @hide
 */
@FlaggedApi(Flags.FLAG_CHANGE_GET_ADAS_ALLOWLIST_FROM_HIDDEN_TO_SYSTEM)
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
@Immutable
@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class PackageTagsMap implements Parcelable {

    // an empty set value matches any attribution tag (ie, wildcard)
    private final ArrayMap<String, ArraySet<String>> mPackageTags;

    private PackageTagsMap(@NonNull ArrayMap<String, ArraySet<String>> packageTags) {
        mPackageTags = Objects.requireNonNull(packageTags);
    }

    /** Returns true if this instance is empty; */
    public boolean isEmpty() {
        return mPackageTags.isEmpty();
    }

    /**
     * Returns true if the given package is found within this instance. If this returns true this
     * does not imply anything about whether any given attribution tag under the given package name
     * is present.
     */
    public boolean containsPackage(@NonNull String packageName) {
        return mPackageTags.containsKey(packageName);
    }

    /**
     * Returns true if the given attribution tag is found within this instance under any package.
     * Only returns true if the attribution tag literal is found, not if any package contains the
     * set of all attribution tags.
     *
     * @hide
     */
    public boolean containsTag(@NonNull String attributionTag) {
        final int size = mPackageTags.size();
        for (int i = 0; i < size; i++) {
            ArraySet<String> tags = mPackageTags.valueAt(i);
            if (tags.contains(attributionTag)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns true if all attribution tags under the given package are contained within this
     * instance.
     */
    public boolean containsPackageWithAllTags(@NonNull String packageName) {
        Set<String> tags = mPackageTags.get(packageName);
        return tags != null && tags.isEmpty();
    }

    /** Returns true if the given package and attribution tag are contained within this instance. */
    public boolean contains(@NonNull String packageName, @Nullable String attributionTag) {
        Set<String> tags = mPackageTags.get(packageName);
        if (tags == null) {
            return false;
        } else if (tags.isEmpty()) {
            // our tags are the full set, so we contain any attribution tag
            return true;
        } else {
            return tags.contains(attributionTag);
        }
    }

    /** Returns true if the given PackageTagsMap is a subset of this instance. */
    public boolean containsAll(@NonNull PackageTagsMap packageTagsMap) {
        int otherSize = packageTagsMap.mPackageTags.size();
        if (otherSize > mPackageTags.size()) {
            return false;
        }

        for (int i = 0; i < otherSize; i++) {
            String packageName = packageTagsMap.mPackageTags.keyAt(i);
            ArraySet<String> tags = mPackageTags.get(packageName);
            if (tags == null) {
                return false;
            }
            if (tags.isEmpty()) {
                // our tags are the full set, so we contain whatever the other tags are
                continue;
            }
            ArraySet<String> otherTags = packageTagsMap.mPackageTags.valueAt(i);
            if (otherTags.isEmpty()) {
                // other tags are the full set, so we can't contain them
                return false;
            }
            if (!tags.containsAll(otherTags)) {
                return false;
            }
        }

        return true;
    }

    /** Returns all packages that possess at least one attribution tag. */
    public @NonNull Set<String> getPackages() {
        return mPackageTags.keySet().stream().collect(Collectors.toSet());
    }

    public static final @NonNull Parcelable.Creator<PackageTagsMap> CREATOR =
            new Parcelable.Creator<PackageTagsMap>() {
                @SuppressWarnings("unchecked")
                @Override
                public PackageTagsMap createFromParcel(Parcel in) {
                    int count = in.readInt();
                    ArrayMap<String, ArraySet<String>> packageTags = new ArrayMap<>(count);
                    for (int i = 0; i < count; i++) {
                        String key = in.readString8();
                        ArraySet<String> value = (ArraySet<String>) in.readArraySet(null);
                        packageTags.append(key, value);
                    }
                    return new PackageTagsMap(packageTags);
                }

                @Override
                public PackageTagsMap[] newArray(int size) {
                    return new PackageTagsMap[size];
                }
            };

    @Override
    public void writeToParcel(@NonNull Parcel parcel, int flags) {
        int count = mPackageTags.size();
        parcel.writeInt(count);
        for (int i = 0; i < count; i++) {
            parcel.writeString8(mPackageTags.keyAt(i));
            parcel.writeArraySet(mPackageTags.valueAt(i));
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof PackageTagsMap)) {
            return false;
        }

        PackageTagsMap that = (PackageTagsMap) o;
        return mPackageTags.equals(that.mPackageTags);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mPackageTags);
    }

    @Override
    public @NonNull String toString() {
        return mPackageTags.toString();
    }

    /** @hide */
    public void dump(PrintWriter pw) {
        int size = mPackageTags.size();
        for (int i = 0; i < size; i++) {
            String packageName = mPackageTags.keyAt(i);
            pw.print(packageName);
            pw.print("[");
            int tagsSize = mPackageTags.valueAt(i).size();
            if (tagsSize == 0) {
                pw.print("*");
            } else {
                for (int j = 0; j < tagsSize; j++) {
                    String attributionTag = mPackageTags.valueAt(i).valueAt(j);
                    if (j > 0) {
                        pw.print(", ");
                    }
                    if (attributionTag != null && attributionTag.startsWith(packageName)) {
                        pw.print(attributionTag.substring(packageName.length()));
                    } else {
                        pw.print(attributionTag);
                    }
                }
            }
            pw.println("]");
        }
    }

    /** Builder class for {@link PackageTagsMap}. */
    public static final class Builder {

        private final ArrayMap<String, ArraySet<String>> mPackageTags;

        /** Creates a new builder. */
        public Builder() {
            mPackageTags = new ArrayMap<>();
        }

        /** Creates a new builder with the given initial capacity. */
        public Builder(int capacity) {
            mPackageTags = new ArrayMap<>(capacity);
        }

        /** Adds all attribution tags under the specified package to the builder. */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder add(@NonNull String packageName) {
            mPackageTags.computeIfAbsent(packageName, p -> new ArraySet<>()).clear();
            return this;
        }

        /** Adds the specified package and attribution tag to the builder. */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder add(@NonNull String packageName, @Nullable String attributionTag) {
            ArraySet<String> tags = mPackageTags.get(packageName);
            if (tags == null) {
                tags = new ArraySet<>(1);
                tags.add(attributionTag);
                mPackageTags.put(packageName, tags);
            } else if (!tags.isEmpty()) {
                tags.add(attributionTag);
            }

            return this;
        }

        /**
         * Adds the specified package and set of attribution tags to the builder.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder add(
                @NonNull String packageName, @NonNull Collection<String> attributionTags) {
            if (attributionTags.isEmpty()) {
                // the input is not allowed to specify a full set by passing in an empty collection
                return this;
            }

            ArraySet<String> tags = mPackageTags.get(packageName);
            if (tags == null) {
                tags = new ArraySet<>(attributionTags);
                mPackageTags.put(packageName, tags);
            } else if (!tags.isEmpty()) {
                // if we contain the full set, already done, otherwise add all the tags
                tags.addAll(attributionTags);
            }

            return this;
        }

        /** Adds the specified {@link PackageTagsMap} to the builder. */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder addAll(@NonNull PackageTagsMap packageTagsMap) {
            return addAll(packageTagsMap.mPackageTags);
        }

        /**
         * Adds the given map of package to attribution tags to the builder. An empty set of
         * attribution tags is interpreted to imply all attribution tags under that package.
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder addAll(@NonNull Map<String, ? extends Set<String>> packageTagsMap) {
            mPackageTags.ensureCapacity(packageTagsMap.size());
            for (Map.Entry<String, ? extends Set<String>> entry : packageTagsMap.entrySet()) {
                Set<String> newTags = entry.getValue();
                if (newTags.isEmpty()) {
                    add(entry.getKey());
                } else {
                    add(entry.getKey(), newTags);
                }
            }

            return this;
        }

        /**
         * Removes all attribution tags under the specified package from the builder.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder remove(@NonNull String packageName) {
            mPackageTags.remove(packageName);
            return this;
        }

        /**
         * Removes the specified package and attribution tag from the builder if and only if the
         * specified attribution tag is listed explicitly under the package. If the package contains
         * all possible attribution tags, then nothing will be removed.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder remove(
                @NonNull String packageName, @Nullable String attributionTag) {
            ArraySet<String> tags = mPackageTags.get(packageName);
            if (tags != null && tags.remove(attributionTag) && tags.isEmpty()) {
                mPackageTags.remove(packageName);
            }
            return this;
        }

        /**
         * Removes the specified package and set of attribution tags from the builder if and only if
         * the specified set of attribution tags are listed explicitly under the package. If the
         * package contains all possible attribution tags, then nothing will be removed.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder remove(
                @NonNull String packageName, @NonNull Collection<String> attributionTags) {
            if (attributionTags.isEmpty()) {
                // the input is not allowed to specify a full set by passing in an empty collection
                return this;
            }

            ArraySet<String> tags = mPackageTags.get(packageName);
            if (tags != null && tags.removeAll(attributionTags) && tags.isEmpty()) {
                mPackageTags.remove(packageName);
            }
            return this;
        }

        /**
         * Removes the specified {@link PackageTagsMap} from the builder. If a package contains all
         * possible attribution tags, it will only be removed if the package in the removed {@link
         * PackageTagsMap} also contains all possible attribution tags.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder removeAll(@NonNull PackageTagsMap packageTagsMap) {
            return removeAll(packageTagsMap.mPackageTags);
        }

        /**
         * Removes the given map of package to attribution tags to the builder. An empty set of
         * attribution tags is interpreted to imply all attribution tags under that package. If a
         * package contains all possible attribution tags, it will only be removed if the package in
         * the removed map also contains all possible attribution tags.
         *
         * @hide
         */
        @SuppressLint("MissingGetterMatchingBuilder")
        public @NonNull Builder removeAll(
                @NonNull Map<String, ? extends Set<String>> packageTagsMap) {
            for (Map.Entry<String, ? extends Set<String>> entry : packageTagsMap.entrySet()) {
                Set<String> removedTags = entry.getValue();
                if (removedTags.isEmpty()) {
                    // if removing the full set, drop the package completely
                    remove(entry.getKey());
                } else {
                    remove(entry.getKey(), removedTags);
                }
            }

            return this;
        }

        /**
         * Clears the builder.
         *
         * @hide
         */
        public @NonNull Builder clear() {
            mPackageTags.clear();
            return this;
        }

        /** Constructs a new {@link PackageTagsMap}. */
        public @NonNull PackageTagsMap build() {
            return new PackageTagsMap(copy(mPackageTags));
        }

        private static ArrayMap<String, ArraySet<String>> copy(
                ArrayMap<String, ArraySet<String>> value) {
            int size = value.size();
            ArrayMap<String, ArraySet<String>> copy = new ArrayMap<>(size);
            for (int i = 0; i < size; i++) {
                String packageName = value.keyAt(i);
                ArraySet<String> tags = new ArraySet<>(Objects.requireNonNull(value.valueAt(i)));
                copy.append(packageName, tags);
            }
            return copy;
        }
    }
}
+0 −159

File deleted.

Preview size limit exceeded, changes collapsed.

Loading