diff options
| -rw-r--r-- | core/api/system-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/os/BaseBundle.java | 52 | ||||
| -rw-r--r-- | core/java/android/os/Bundle.java | 30 | ||||
| -rw-r--r-- | core/java/android/os/Parcel.java | 23 | ||||
| -rw-r--r-- | core/java/android/service/tracing/TraceReportService.java | 12 | ||||
| -rw-r--r-- | packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java | 8 |
6 files changed, 87 insertions, 40 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 2c7f456c5e76..5c6076be4dc9 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10131,8 +10131,6 @@ package android.service.tracing { public class TraceReportService extends android.app.Service { ctor public TraceReportService(); - method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); - method public boolean onMessage(@NonNull android.os.Message); method public void onReportTrace(@NonNull android.service.tracing.TraceReportService.TraceParams); } diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index ad3de25fecc2..244335d3aa06 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -31,7 +31,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.Serializable; import java.util.ArrayList; import java.util.Set; -import java.util.function.Supplier; +import java.util.function.Function; /** * A mapping from String keys to values of various types. In most cases, you @@ -252,11 +252,10 @@ public class BaseBundle { if (size == 0) { return null; } - Object o = getValueAt(0); try { - return (String) o; - } catch (ClassCastException e) { - typeWarning("getPairValue()", o, "String", e); + return getValueAt(0, String.class); + } catch (ClassCastException | BadParcelableException e) { + typeWarning("getPairValue()", /* value */ null, "String", e); return null; } } @@ -309,7 +308,7 @@ public class BaseBundle { } for (int i = 0, n = mMap.size(); i < n; i++) { // Triggers deserialization of i-th item, if needed - getValueAt(i); + getValueAt(i, /* clazz */ null); } } } @@ -324,8 +323,21 @@ public class BaseBundle { * @hide */ final Object getValue(String key) { + return getValue(key, /* clazz */ null); + } + + /** + * Returns the value for key {@code key} for expected return type {@param clazz} (or {@code + * null} for no type check). + * + * This call should always be made after {@link #unparcel()} or inside a lock after making sure + * {@code mMap} is not null. + * + * @hide + */ + final <T> T getValue(String key, @Nullable Class<T> clazz) { int i = mMap.indexOfKey(key); - return (i >= 0) ? getValueAt(i) : null; + return (i >= 0) ? getValueAt(i, clazz) : null; } /** @@ -336,11 +348,12 @@ public class BaseBundle { * * @hide */ - final Object getValueAt(int i) { + @SuppressWarnings("unchecked") + final <T> T getValueAt(int i, @Nullable Class<T> clazz) { Object object = mMap.valueAt(i); - if (object instanceof Supplier<?>) { + if (object instanceof Function<?, ?>) { try { - object = ((Supplier<?>) object).get(); + object = ((Function<Class<?>, ?>) object).apply(clazz); } catch (BadParcelableException e) { if (sShouldDefuse) { Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e); @@ -351,7 +364,7 @@ public class BaseBundle { } mMap.setValueAt(i, object); } - return object; + return (clazz != null) ? clazz.cast(object) : (T) object; } private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel, @@ -528,7 +541,7 @@ public class BaseBundle { } else { // Following semantic above of failing in case we get a serialized value vs a // deserialized one, we'll compare the map. If a certain element hasn't been - // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's + // deserialized yet, it's a function object (or more specifically a LazyValue, but let's // pretend we don't know that here :P), we'll use that element's equality comparison as // map naturally does. That will takes care of comparing the payload if needed (see // Parcel.readLazyValue() for details). @@ -982,15 +995,19 @@ public class BaseBundle { } // Log a message if the value was non-null but not of the expected type - void typeWarning(String key, Object value, String className, - Object defaultValue, ClassCastException e) { + void typeWarning(String key, @Nullable Object value, String className, + Object defaultValue, RuntimeException e) { StringBuilder sb = new StringBuilder(); sb.append("Key "); sb.append(key); sb.append(" expected "); sb.append(className); - sb.append(" but value was a "); - sb.append(value.getClass().getName()); + if (value != null) { + sb.append(" but value was a "); + sb.append(value.getClass().getName()); + } else { + sb.append(" but value was of a different type "); + } sb.append(". The default value "); sb.append(defaultValue); sb.append(" was returned."); @@ -998,8 +1015,7 @@ public class BaseBundle { Log.w(TAG, "Attempt to cast generated internal exception:", e); } - void typeWarning(String key, Object value, String className, - ClassCastException e) { + void typeWarning(String key, @Nullable Object value, String className, RuntimeException e) { typeWarning(key, value, className, "<null>", e); } diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index b2bbfd6c163d..2b13f20ffe6d 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -16,6 +16,9 @@ package android.os; +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; @@ -914,6 +917,33 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { /** * Returns the value associated with the given key, or {@code null} if + * no mapping of the desired type exists for the given key or a {@code null} + * value is explicitly associated with the key. + * + * <p><b>Note: </b> if the expected value is not a class provided by the Android platform, + * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first. + * Otherwise, this method might throw an exception or return {@code null}. + * + * @param key a String, or {@code null} + * @param clazz The type of the object expected or {@code null} for performing no checks. + * @return a Parcelable value, or {@code null} + * + * @hide + */ + @SuppressWarnings("unchecked") + @Nullable + public <T> T getParcelable(@Nullable String key, @NonNull Class<T> clazz) { + unparcel(); + try { + return getValue(key, requireNonNull(clazz)); + } catch (ClassCastException | BadParcelableException e) { + typeWarning(key, /* value */ null, "Parcelable", e); + return null; + } + } + + /** + * Returns the value associated with the given key, or {@code null} if * no mapping of the desired type exists for the given key or a null * value is explicitly associated with the key. * diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 13d1d96fadc8..32cee94506a2 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -4312,18 +4312,19 @@ public final class Parcel { } /** - * This will return a {@link Supplier} for length-prefixed types that deserializes the object - * when {@link Supplier#get()} is called, for other types it will return the object itself. + * This will return a {@link Function} for length-prefixed types that deserializes the object + * when {@link Function#apply} is called with the expected class of the return object (or {@code + * null} for no type check), for other types it will return the object itself. * - * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you - * shouldn't recycle the parcel, not at least until all objects have been retrieved. No + * <p>After calling {@link Function#apply(Object)} the parcel cursor will not change. Note that + * you shouldn't recycle the parcel, not at least until all objects have been retrieved. No * synchronization attempts are made. * - * </p>The supplier returned implements {@link #equals(Object)} and {@link #hashCode()}. Two - * suppliers are equal if either of the following is true: + * </p>The function returned implements {@link #equals(Object)} and {@link #hashCode()}. Two + * function objects are equal if either of the following is true: * <ul> - * <li>{@link Supplier#get()} has been called on both and both objects returned are equal. - * <li>{@link Supplier#get()} hasn't been called on either one and everything below is true: + * <li>{@link Function#apply} has been called on both and both objects returned are equal. + * <li>{@link Function#apply} hasn't been called on either one and everything below is true: * <ul> * <li>The {@code loader} parameters used to retrieve each are equal. * <li>They both have the same type. @@ -4350,7 +4351,7 @@ public final class Parcel { } - private static final class LazyValue implements Supplier<Object> { + private static final class LazyValue implements Function<Class<?>, Object> { /** * | 4B | 4B | * mSource = Parcel{... | type | length | object | ...} @@ -4382,7 +4383,7 @@ public final class Parcel { } @Override - public Object get() { + public Object apply(@Nullable Class<?> clazz) { Parcel source = mSource; if (source != null) { synchronized (source) { @@ -4391,7 +4392,7 @@ public final class Parcel { int restore = source.dataPosition(); try { source.setDataPosition(mPosition); - mObject = source.readValue(mLoader); + mObject = source.readValue(mLoader, clazz); } finally { source.setDataPosition(restore); } diff --git a/core/java/android/service/tracing/TraceReportService.java b/core/java/android/service/tracing/TraceReportService.java index 3d16a3d41ea3..6fdc8e8eb961 100644 --- a/core/java/android/service/tracing/TraceReportService.java +++ b/core/java/android/service/tracing/TraceReportService.java @@ -112,7 +112,6 @@ public class TraceReportService extends Service { } } - // Methods to override. /** * Called when a trace is reported and sent to this class. * @@ -123,15 +122,10 @@ public class TraceReportService extends Service { public void onReportTrace(@NonNull TraceParams args) { } - // Optional methods to override. - // Realistically, these methods are internal implementation details but since this class is - // a SystemApi, it's better to err on the side of flexibility just in-case we need to override - // these methods down the line. - /** * Handles binder calls from system_server. */ - public boolean onMessage(@NonNull Message msg) { + private boolean onMessage(@NonNull Message msg) { if (msg.what == MSG_REPORT_TRACE) { if (!(msg.obj instanceof TraceReportParams)) { Log.e(TAG, "Received invalid type for report trace message."); @@ -153,10 +147,12 @@ public class TraceReportService extends Service { /** * Returns an IBinder for handling binder calls from system_server. + * + * @hide */ @Nullable @Override - public IBinder onBind(@NonNull Intent intent) { + public final IBinder onBind(@NonNull Intent intent) { if (mMessenger == null) { mMessenger = new Messenger(new Handler(Looper.getMainLooper(), this::onMessage)); } diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java index eeb56d05e706..b1936231148c 100644 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java @@ -1875,7 +1875,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void deleteKernelTagData(int uid) { try { mCookieTagMap.forEach((key, value) -> { - if (value.uid == uid) { + // If SkDestroyListener deletes the socket tag while this code is running, + // forEach will either restart iteration from the beginning or return null, + // depending on when the deletion happens. + // If it returns null, continue iteration to delete the data and in fact it would + // just iterate from first key because BpfMap#getNextKey would return first key + // if the current key is not exist. + if (value != null && value.uid == uid) { try { mCookieTagMap.deleteEntry(key); } catch (ErrnoException e) { |