diff options
56 files changed, 2154 insertions, 1418 deletions
diff --git a/apex/blobstore/README.md b/apex/blobstore/README.md new file mode 100644 index 000000000000..69af436bf325 --- /dev/null +++ b/apex/blobstore/README.md @@ -0,0 +1,125 @@ +<!-- + Copyright (C) 2021 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 +--> + +# BlobStore Manager + +## Introduction +* BlobStoreManager is a system service added in Android R release that facilitates sharing of + data blobs among apps. +* Apps that would like to share data blobs with other apps can do so by contributing those + data blobs with the System and can choose how they would like the System to share the data blobs + with other apps. +* Apps can access data blobs shared by other apps from the System using checksum of the data blobs + (plus some other data attributes. More details [below](#blob-handle)). +* The APIs provided by the BlobStoreManager are meant to reduce storage and network usage by + reusing the data available on the device instead of downloading the same data again and having + multiple copies of the same data on disk. +* It is not meant to provide access to the data which apps otherwise would not be able to access. + In other words, if an app’s only means of obtaining access to certain data is through + BlobStoreManager, then that use case is not really intended or supported. +* For example, if earlier an app was downloading certain shared data from a server, then by using + BlobStoreManager, it can first check whether or not the data is already available on the device + before downloading. + +## Concepts +### Blob handle +Blob handle is the identifier of the data and it is what apps need to use for referring to the +data blobs. Currently, this is made of following bits of information: +* SHA256 checksum of data +* Data label: A user readable string that indicates what the data blob is. + This is meant to be used when surfacing a list of blobs to the user. +* Data expiry time: A timestamp after which the data blob should be considered invalid and not + allowed to be accessed by any app. +* Data tag: An opaque string associated with the blob. System does not interpret this in any way or + use it for any purposes other than when checking whether two Blob handle identifiers are referring + to the same data blob. This is meant to be used by the apps, either for categorization for + data blobs or for adding additional identifiers. For example, an app can add tags like + *machine_learning* or *media* depending on the data blob if necessary. + +When comparing two Blob handles, the System will compare all the pieces of information above and +only when two Blob handles are equal, the data blobs corresponding to those identifiers are +considered equal. + +### Blob sharing session +Session is a way to allow apps to contribute data over multiple time intervals. Each session is +associated with a unique Identifier that is created and obtained by the apps by calling +[BlobStoreManager#createSession](https://developer.android.com/reference/android/app/blob/BlobStoreManager#createSession(android.app.blob.BlobHandle)). +Apps can save the Identifier associated with a session and use it to open and close it +multiple times for contributing the data. For example, if an app is downloading +some content over the network, it can start a Session and start contributing this data to the +System immediately and if the network connection is lost for any reason, the app can close this +session. When the download resumes, the app can reopen the session and start contributing again. +Note that once the entire data is contributed, the app has no reason to hold on to the Session Id. + +### Blob commit +Since a data blob can be contributed in a session over multiple time intervals, an app closing a +session does not imply that the contribution is completed. So, *commit* is added as an explicit +event / signal for the app to indicate that the contribution of the data blob is completed. +At this point, the System can verify the data blob does indeed correspond to the Blob handle used +by the app and prevent the app from making any further modifications to the data blob. Once the +data blob is committed and verified by the System, it is available for other applications to access. + +### Access modes +When an application contributes a data blob to the System, it can choose to specify how it would +like the System to share this data blob with other applications. Access modes refer to the type of +access that apps specified when contributing a data blob. As of Android S release, there are +four access modes: +* Allow specific packages: Apps can specify a specific set of applications that are allowed to + access their data blob. +* Allow packages with the same signature: Apps can specify that only the applications that are + signed with the same certificate as them can access their data blob. +* Allow public access: Apps can specify that any other app on the device can access their data blob. +* Allow private access: Apps can specify that no other app can access their data blob unless they + happen to contribute the same data blob. + * Note that in this case, two apps might download the same data blob and contribute to the System + in which case we are not saving anything in terms of bandwidth usage, but we would still be + saving disk usage since we would be keeping only one copy of data on disk. + +### Lease +Leasing a blob is a way to specify that an application is interested in using a data blob +and would like the System to not delete this data blob. Applications can also access a blob +without holding a lease on it, in which case the System can choose to delete the data blob at any +time. So, if an application wants to make sure a data blob is available for access for a certain +period, it is recommended that the application acquire a lease on the data blob. Applications can +either specify upfront how long they would like to hold the lease for (which is called the lease +expiry time), or they can acquire a lease without specifying a time period and release the lease +when they are done with the data blob. + +## Sharing data blobs across users +By default, data blobs are only accessible to applications in the user in which the data blob was +contributed, but if an application holds the permission +[ACCESS_BLOBS_ACROSS_USERS](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BLOBS_ACROSS_USERS), +then they are allowed to access blobs that are contributed by the applications in the other users. +As of Android S, this permission is only available to following set of applications: +* Apps signed with the platform certificate +* Privileged applications +* Applications holding the + [ASSISTANT](https://developer.android.com/reference/android/app/role/RoleManager#ROLE_ASSISTANT) + role +* Development applications + +Note that the access modes that applications choose while committing the data blobs still apply +when these data blobs are accessed across users. So for example, if *appA* contributed a +data blob in *user0* and specified to share this data blob with only a specific set of +applications [*appB*, *appC*], then *appD* on *user10* will not be able to access this data blob +even if the app is granted the `ACCESS_BLOBS_ACROSS_USERS` permission. + +When apps that are allowed to access blobs across users +(i.e. those holding the permission `ACCESS_BLOBS_ACROSS_USERS`) try to access a data blob, +they can do so as if it is any other data blob. In other words, the applications don’t need to +know where the data blob is contributed, because the System will automatically check and will +allow access if this data blob is available either on the user in which the calling application +is running in or other users.
\ No newline at end of file diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS index 69dfcc98340d..062ffd41348a 100644 --- a/cmds/idmap2/OWNERS +++ b/cmds/idmap2/OWNERS @@ -1,4 +1,4 @@ set noparent toddke@google.com -rtmitchell@google.com -patb@google.com
\ No newline at end of file +patb@google.com +zyy@google.com diff --git a/core/api/current.txt b/core/api/current.txt index 9d1a171088eb..641f71be8e40 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31427,6 +31427,8 @@ package android.os { method @Nullable public double[] createDoubleArray(); method @Nullable public float[] createFloatArray(); method @Nullable public int[] createIntArray(); + method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>); + method @Nullable public <T extends android.os.IInterface> java.util.ArrayList<T> createInterfaceArrayList(@NonNull java.util.function.Function<android.os.IBinder,T>); method @Nullable public long[] createLongArray(); method @Nullable public String[] createStringArray(); method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList(); @@ -31467,6 +31469,8 @@ package android.os { method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader); method public int readInt(); method public void readIntArray(@NonNull int[]); + method public <T extends android.os.IInterface> void readInterfaceArray(@NonNull T[], @NonNull java.util.function.Function<android.os.IBinder,T>); + method public <T extends android.os.IInterface> void readInterfaceList(@NonNull java.util.List<T>, @NonNull java.util.function.Function<android.os.IBinder,T>); method public void readList(@NonNull java.util.List, @Nullable ClassLoader); method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>); method public long readLong(); @@ -31519,6 +31523,8 @@ package android.os { method public void writeFloatArray(@Nullable float[]); method public void writeInt(int); method public void writeIntArray(@Nullable int[]); + method public <T extends android.os.IInterface> void writeInterfaceArray(@Nullable T[]); + method public <T extends android.os.IInterface> void writeInterfaceList(@Nullable java.util.List<T>); method public void writeInterfaceToken(@NonNull String); method public void writeList(@Nullable java.util.List); method public void writeLong(long); @@ -40737,11 +40743,11 @@ package android.telephony { } public class CarrierConfigManager { - method @Nullable public android.os.PersistableBundle getConfig(); - method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int); - method @Nullable public android.os.PersistableBundle getConfigForSubId(int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int); method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle); - method public void notifyConfigChangedForSubId(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int); field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1 field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2 diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index c3f9c209fd45..9af6c1b340b6 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -297,6 +297,10 @@ package android.os { method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException; } + public class SystemConfigManager { + method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String); + } + } package android.os.storage { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ac6943c3915e..78e6a07c8705 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8581,7 +8581,6 @@ package android.os { public class SystemConfigManager { method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); - method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index db5dcc5c264b..af59ea1d22ff 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -77,7 +77,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Parcelable; import android.os.PersistableBundle; -import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager.ServiceNotFoundException; @@ -8788,9 +8787,7 @@ public class Activity extends ContextThemeWrapper * the activity is visible after the screen is turned on when the lockscreen is up. In addition, * if this flag is set and the activity calls {@link * KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)} - * the screen will turn on. If the screen is off and device is not secured, this flag can turn - * screen on and dismiss keyguard to make this activity visible and resume, which can be used to - * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP} + * the screen will turn on. * * @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise. * diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS index 91a0abfe711a..3669817e9844 100644 --- a/core/java/android/content/om/OWNERS +++ b/core/java/android/content/om/OWNERS @@ -3,4 +3,4 @@ toddke@android.com toddke@google.com patb@google.com -rtmitchell@google.com +zyy@google.com diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS index bc2355c6af5e..d12d920b2a54 100644 --- a/core/java/android/content/res/OWNERS +++ b/core/java/android/content/res/OWNERS @@ -3,4 +3,4 @@ toddke@android.com toddke@google.com patb@google.com -rtmitchell@google.com +zyy@google.com diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 74506dae329b..ee24084e63c6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -777,8 +777,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * <p> @@ -793,8 +793,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -806,7 +806,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 2a344f6c2b6b..ad3de25fecc2 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -103,7 +103,7 @@ public class BaseBundle { * are unparcelled, mParcelledData willbe set to null. */ @UnsupportedAppUsage - Parcel mParcelledData = null; + volatile Parcel mParcelledData = null; /** * Whether {@link #mParcelledData} was generated by native code or not. @@ -182,13 +182,56 @@ public class BaseBundle { * @param b a Bundle to be copied. */ BaseBundle(BaseBundle b) { - copyInternal(b, false); + this(b, /* deep */ false); } /** - * Special constructor that does not initialize the bundle. + * Constructs a {@link BaseBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - BaseBundle(boolean doInit) { + BaseBundle(BaseBundle from, boolean deep) { + synchronized (from) { + mClassLoader = from.mClassLoader; + + if (from.mMap != null) { + if (!deep) { + mMap = new ArrayMap<>(from.mMap); + } else { + final ArrayMap<String, Object> fromMap = from.mMap; + final int n = fromMap.size(); + mMap = new ArrayMap<>(n); + for (int i = 0; i < n; i++) { + mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); + } + } + } else { + mMap = null; + } + + final Parcel parcelledData; + if (from.mParcelledData != null) { + if (from.isEmptyParcel()) { + parcelledData = NoImagePreloadHolder.EMPTY_PARCEL; + mParcelledByNative = false; + } else { + parcelledData = Parcel.obtain(); + parcelledData.appendFrom(from.mParcelledData, 0, + from.mParcelledData.dataSize()); + parcelledData.setDataPosition(0); + mParcelledByNative = from.mParcelledByNative; + } + } else { + parcelledData = null; + mParcelledByNative = false; + } + + // Keep as last statement to ensure visibility of other fields + mParcelledData = parcelledData; + } } /** @@ -323,8 +366,8 @@ public class BaseBundle { } else { mMap.erase(); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; return; } @@ -358,8 +401,8 @@ public class BaseBundle { if (recycleParcel) { recycleParcel(parcelledData); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; } if (DEBUG) { Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) @@ -501,44 +544,7 @@ public class BaseBundle { mMap.clear(); } - void copyInternal(BaseBundle from, boolean deep) { - synchronized (from) { - if (from.mParcelledData != null) { - if (from.isEmptyParcel()) { - mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(from.mParcelledData, 0, - from.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - mParcelledByNative = from.mParcelledByNative; - } - } else { - mParcelledData = null; - mParcelledByNative = false; - } - - if (from.mMap != null) { - if (!deep) { - mMap = new ArrayMap<>(from.mMap); - } else { - final ArrayMap<String, Object> fromMap = from.mMap; - final int N = fromMap.size(); - mMap = new ArrayMap<>(N); - for (int i = 0; i < N; i++) { - mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); - } - } - } else { - mMap = null; - } - - mClassLoader = from.mClassLoader; - } - } - - Object deepCopyValue(Object value) { + private Object deepCopyValue(Object value) { if (value == null) { return null; } @@ -570,7 +576,7 @@ public class BaseBundle { return value; } - ArrayList deepcopyArrayList(ArrayList from) { + private ArrayList deepcopyArrayList(ArrayList from) { final int N = from.size(); ArrayList out = new ArrayList(N); for (int i=0; i<N; i++) { @@ -1717,9 +1723,9 @@ public class BaseBundle { if (length < 0) { throw new RuntimeException("Bad length in parcel: " + length); } else if (length == 0) { + mParcelledByNative = false; // Empty Bundle or end of data. mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; return; } else if (length % 4 != 0) { throw new IllegalStateException("Bundle length is not aligned by 4: " + length); @@ -1757,8 +1763,8 @@ public class BaseBundle { + ": " + length + " bundle bytes starting at " + offset); p.setDataPosition(0); - mParcelledData = p; mParcelledByNative = isNativeBundle; + mParcelledData = p; } /** {@hide} */ diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 92eb7a5d047e..b2bbfd6c163d 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -102,6 +102,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Constructs a {@link Bundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide + */ + Bundle(Bundle from, boolean deep) { + super(from, deep); + } + + /** * If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast. * Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN} * unset, because scanning a map is slower. We'll do it lazily in @@ -167,13 +179,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Constructs a Bundle without initializing it. - */ - Bundle(boolean doInit) { - super(doInit); - } - - /** * Make a Bundle for a single key/value pair. * * @hide @@ -260,9 +265,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * are referenced as-is and not copied in any way. */ public Bundle deepCopy() { - Bundle b = new Bundle(false); - b.copyInternal(this, true); - return b; + return new Bundle(this, /* deep */ true); } /** @@ -324,28 +327,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { */ public boolean hasFileDescriptors() { if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) { - boolean fdFound = false; // keep going until we find one or run out of data - - if (mParcelledData != null) { - if (mParcelledData.hasFileDescriptors()) { - fdFound = true; - } - } else { - // It's been unparcelled, so we need to walk the map - for (int i=mMap.size()-1; i>=0; i--) { - Object obj = mMap.valueAt(i); - if (Parcel.hasFileDescriptors(obj)) { - fdFound = true; - break; - } - } - } - - if (fdFound) { - mFlags |= FLAG_HAS_FDS; - } else { - mFlags &= ~FLAG_HAS_FDS; - } + Parcel p = mParcelledData; + mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap)) + ? mFlags | FLAG_HAS_FDS + : mFlags & ~FLAG_HAS_FDS; mFlags |= FLAG_HAS_FDS_KNOWN; } return (mFlags & FLAG_HAS_FDS) != 0; diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl index d83d94a8ec77..15e3ce25122b 100644 --- a/core/java/android/os/ISystemConfig.aidl +++ b/core/java/android/os/ISystemConfig.aidl @@ -16,6 +16,8 @@ package android.os; +import android.content.ComponentName; + /** * Binder interface to query SystemConfig in the system server. * {@hide} @@ -44,5 +46,5 @@ interface ISystemConfig { /** * @see SystemConfigManager#getEnabledComponentOverrides */ - List<String> getEnabledComponentOverrides(String packageName); + List<ComponentName> getEnabledComponentOverrides(String packageName); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index dd0cb8cc62ae..5a2f27d83893 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -62,6 +62,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Supplier; /** @@ -178,8 +180,12 @@ import java.util.function.Supplier; * {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()}, * {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])}, * {@link #createBinderArray()}, + * {@link #writeInterfaceArray(T[])}, {@link #readInterfaceArray(T[], Function)}, + * {@link #createInterfaceArray(IntFunction, Function)}, * {@link #writeBinderList(List)}, {@link #readBinderList(List)}, - * {@link #createBinderArrayList()}.</p> + * {@link #createBinderArrayList()}, + * {@link #writeInterfaceList(List)}, {@link #readInterfaceList(List, Function)}, + * {@link #createInterfaceArrayList(Function)}.</p> * * <p>FileDescriptor objects, representing raw Linux file descriptor identifiers, * can be written and {@link ParcelFileDescriptor} objects returned to operate @@ -747,57 +753,70 @@ public final class Parcel { } /** - * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)} - * has file descriptors. + * Check if the object has file descriptors. + * + * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link + * #writeValue(Object)}} * * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method * for that. * - * @throws IllegalArgumentException if you provide any object not supported by above methods. - * Most notably, if you pass {@link Parcel}, this method will throw, for that check - * {@link Parcel#hasFileDescriptors()} + * @throws IllegalArgumentException if you provide any object not supported by above methods + * (including if the unsupported object is inside a nested container). * * @hide */ public static boolean hasFileDescriptors(Object value) { - if (value instanceof LazyValue) { - return ((LazyValue) value).hasFileDescriptors(); + if (value instanceof Parcel) { + Parcel parcel = (Parcel) value; + if (parcel.hasFileDescriptors()) { + return true; + } + } else if (value instanceof LazyValue) { + LazyValue lazy = (LazyValue) value; + if (lazy.hasFileDescriptors()) { + return true; + } } else if (value instanceof Parcelable) { - if ((((Parcelable) value).describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { + Parcelable parcelable = (Parcelable) value; + if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { return true; } - } else if (value instanceof Parcelable[]) { - Parcelable[] array = (Parcelable[]) value; - for (int n = array.length - 1; n >= 0; n--) { - Parcelable p = array[n]; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { + } else if (value instanceof ArrayMap<?, ?>) { + ArrayMap<?, ?> map = (ArrayMap<?, ?>) value; + for (int i = 0, n = map.size(); i < n; i++) { + if (hasFileDescriptors(map.keyAt(i)) + || hasFileDescriptors(map.valueAt(i))) { + return true; + } + } + } else if (value instanceof Map<?, ?>) { + Map<?, ?> map = (Map<?, ?>) value; + for (Map.Entry<?, ?> entry : map.entrySet()) { + if (hasFileDescriptors(entry.getKey()) + || hasFileDescriptors(entry.getValue())) { + return true; + } + } + } else if (value instanceof List<?>) { + List<?> list = (List<?>) value; + for (int i = 0, n = list.size(); i < n; i++) { + if (hasFileDescriptors(list.get(i))) { return true; } } } else if (value instanceof SparseArray<?>) { SparseArray<?> array = (SparseArray<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.valueAt(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && (p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { - return true; - } + for (int i = 0, n = array.size(); i < n; i++) { + if (hasFileDescriptors(array.valueAt(i))) { + return true; } } - } else if (value instanceof ArrayList<?>) { - ArrayList<?> array = (ArrayList<?>) value; - for (int n = array.size() - 1; n >= 0; n--) { - Object object = array.get(n); - if (object instanceof Parcelable) { - Parcelable p = (Parcelable) object; - if (p != null && ((p.describeContents() - & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) { - return true; - } + } else if (value instanceof Object[]) { + Object[] array = (Object[]) value; + for (int i = 0, n = array.length; i < n; i++) { + if (hasFileDescriptors(array[i])) { + return true; } } } else { @@ -1717,6 +1736,30 @@ public final class Parcel { } /** + * Flatten a homogeneous array containing an IInterface type into the parcel, + * at the current dataPosition() and growing dataCapacity() if needed. The + * type of the objects in the array must be one that implements IInterface. + * + * @param val The array of objects to be written. + * + * @see #createInterfaceArray + * @see #readInterfaceArray + * @see IInterface + */ + public final <T extends IInterface> void writeInterfaceArray( + @SuppressLint("ArrayReturn") @Nullable T[] val) { + if (val != null) { + int N = val.length; + writeInt(N); + for (int i=0; i<N; i++) { + writeStrongInterface(val[i]); + } + } else { + writeInt(-1); + } + } + + /** * @hide */ public final void writeCharSequenceArray(@Nullable CharSequence[] val) { @@ -1772,6 +1815,50 @@ public final class Parcel { } /** + * Read and return a new array of T (IInterface) from the parcel. + * + * @return the IInterface array of type T + * @param newArray a function to create an array of T with a given length + * @param asInterface a function to convert IBinder object into T (IInterface) + */ + @SuppressLint({"ArrayReturn", "NullableCollection", "SamShouldBeLast"}) + @Nullable + public final <T extends IInterface> T[] createInterfaceArray( + @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N >= 0) { + T[] val = newArray.apply(N); + for (int i=0; i<N; i++) { + val[i] = asInterface.apply(readStrongBinder()); + } + return val; + } else { + return null; + } + } + + /** + * Read an array of T (IInterface) from a parcel. + * + * @param asInterface a function to convert IBinder object into T (IInterface) + * + * @throws BadParcelableException Throws BadParcelableException if the length of `val` + * mismatches the number of items in the parcel. + */ + public final <T extends IInterface> void readInterfaceArray( + @SuppressLint("ArrayReturn") @NonNull T[] val, + @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N == val.length) { + for (int i=0; i<N; i++) { + val[i] = asInterface.apply(readStrongBinder()); + } + } else { + throw new BadParcelableException("bad array lengths"); + } + } + + /** * Flatten a List containing a particular object type into the parcel, at * the current dataPosition() and growing dataCapacity() if needed. The * type of the objects in the list must be one that implements Parcelable. @@ -1885,6 +1972,28 @@ public final class Parcel { } /** + * Flatten a {@code List} containing T (IInterface) objects into this parcel + * at the current position. They can later be retrieved with + * {@link #createInterfaceArrayList} or {@link #readInterfaceList}. + * + * @see #createInterfaceArrayList + * @see #readInterfaceList + */ + public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) { + if (val == null) { + writeInt(-1); + return; + } + int N = val.size(); + int i=0; + writeInt(N); + while (i < N) { + writeStrongInterface(val.get(i)); + i++; + } + } + + /** * Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel * at the current position. They can later be retrieved using * {@link #readParcelableList(List, ClassLoader)} if required. @@ -3367,6 +3476,32 @@ public final class Parcel { } /** + * Read and return a new ArrayList containing T (IInterface) objects from + * the parcel that was written with {@link #writeInterfaceList} at the + * current dataPosition(). Returns null if the + * previously written list object was null. + * + * @return A newly created ArrayList containing T (IInterface) + * + * @see #writeInterfaceList + */ + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable + public final <T extends IInterface> ArrayList<T> createInterfaceArrayList( + @NonNull Function<IBinder, T> asInterface) { + int N = readInt(); + if (N < 0) { + return null; + } + ArrayList<T> l = new ArrayList<T>(N); + while (N > 0) { + l.add(asInterface.apply(readStrongBinder())); + N--; + } + return l; + } + + /** * Read into the given List items String objects that were written with * {@link #writeStringList} at the current dataPosition(). * @@ -3409,6 +3544,28 @@ public final class Parcel { } /** + * Read into the given List items IInterface objects that were written with + * {@link #writeInterfaceList} at the current dataPosition(). + * + * @see #writeInterfaceList + */ + public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list, + @NonNull Function<IBinder, T> asInterface) { + int M = list.size(); + int N = readInt(); + int i = 0; + for (; i < M && i < N; i++) { + list.set(i, asInterface.apply(readStrongBinder())); + } + for (; i<N; i++) { + list.add(asInterface.apply(readStrongBinder())); + } + for (; i<M; i++) { + list.remove(N); + } + } + + /** * Read the list of {@code Parcelable} objects at the current data position into the * given {@code list}. The contents of the {@code list} are replaced. If the serialized * list was {@code null}, {@code list} is cleared. diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index 7b55e710caeb..f4edcb1317f4 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -156,10 +156,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa } /** - * Constructs a PersistableBundle without initializing it. + * Constructs a {@link PersistableBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - PersistableBundle(boolean doInit) { - super(doInit); + PersistableBundle(PersistableBundle from, boolean deep) { + super(from, deep); } /** @@ -190,9 +195,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa * are referenced as-is and not copied in any way. */ public PersistableBundle deepCopy() { - PersistableBundle b = new PersistableBundle(false); - b.copyInternal(this, true); - return b; + return new PersistableBundle(this, /* deep */ true); } /** diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java index a6316df0780c..cde2063fdba5 100644 --- a/core/java/android/os/SystemConfigManager.java +++ b/core/java/android/os/SystemConfigManager.java @@ -17,10 +17,10 @@ package android.os; import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.content.ComponentName; import android.content.Context; import android.util.ArraySet; import android.util.Log; @@ -138,9 +138,9 @@ public class SystemConfigManager { * @return The enabled component * {@hide} */ - @SystemApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull - public List<String> getEnabledComponentOverrides(@NonNull String packageName) { + public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) { try { return mInterface.getEnabledComponentOverrides(packageName); } catch (RemoteException e) { diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index fa1e9d4afcdf..a62ddd084aab 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -351,6 +351,7 @@ message ActivityRecordProto { optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; + optional float min_aspect_ratio = 33; } /* represents WindowToken */ diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS index d80699de8a2d..f49e80ae16b1 100644 --- a/libs/WindowManager/Shell/tests/OWNERS +++ b/libs/WindowManager/Shell/tests/OWNERS @@ -1,3 +1,4 @@ # Bug component: 909476 # includes OWNERS from parent directories natanieljr@google.com +pablogamito@google.com diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS index 610fd80fe73c..17f5164cf417 100644 --- a/libs/androidfw/OWNERS +++ b/libs/androidfw/OWNERS @@ -1,6 +1,6 @@ set noparent toddke@google.com -rtmitchell@google.com +zyy@google.com patb@google.com per-file CursorWindow.cpp=omakoto@google.com diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 8b9153621165..de31a7f5c184 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -60,10 +60,10 @@ import java.util.concurrent.locks.ReentrantLock; with {@link MediaExtractor}, {@link MediaSync}, {@link MediaMuxer}, {@link MediaCrypto}, {@link MediaDrm}, {@link Image}, {@link Surface}, and {@link AudioTrack}.) <p> - <center><object style="width: 540px; height: 205px;" type="image/svg+xml" - data="../../../images/media/mediacodec_buffers.svg"><img - src="../../../images/media/mediacodec_buffers.png" style="width: 540px; height: 205px" - alt="MediaCodec buffer flow diagram"></object></center> + <center> + <img src="../../../images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px" + alt="MediaCodec buffer flow diagram"> + </center> <p> In broad terms, a codec processes input data to generate output data. It processes data asynchronously and uses a set of input and output buffers. At a simplistic level, you request @@ -268,10 +268,10 @@ import java.util.concurrent.locks.ReentrantLock; Uninitialized, Configured and Error, whereas the Executing state conceptually progresses through three sub-states: Flushed, Running and End-of-Stream. <p> - <center><object style="width: 516px; height: 353px;" type="image/svg+xml" - data="../../../images/media/mediacodec_states.svg"><img - src="../../../images/media/mediacodec_states.png" style="width: 519px; height: 356px" - alt="MediaCodec state diagram"></object></center> + <center> + <img src="../../../images/media/mediacodec_states.svg" style="width: 519px; height: 356px" + alt="MediaCodec state diagram"> + </center> <p> When you create a codec using one of the factory methods, the codec is in the Uninitialized state. First, you need to configure it via {@link #configure configure(…)}, which brings @@ -513,10 +513,10 @@ import java.util.concurrent.locks.ReentrantLock; Similarly, upon an initial call to {@code start} the codec will move directly to the Running sub-state and start passing available input buffers via the callback. <p> - <center><object style="width: 516px; height: 353px;" type="image/svg+xml" - data="../../../images/media/mediacodec_async_states.svg"><img - src="../../../images/media/mediacodec_async_states.png" style="width: 516px; height: 353px" - alt="MediaCodec state diagram for asynchronous operation"></object></center> + <center> + <img src="../../../images/media/mediacodec_async_states.svg" style="width: 516px; height: 353px" + alt="MediaCodec state diagram for asynchronous operation"> + </center> <p> MediaCodec is typically used like this in asynchronous mode: <pre class=prettyprint> diff --git a/mms/OWNERS b/mms/OWNERS index 7f05a2a24d6e..f56845ed80c7 100644 --- a/mms/OWNERS +++ b/mms/OWNERS @@ -3,16 +3,15 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com -amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS index 0d23f053499c..b9de5a3919f5 100644 --- a/packages/CarrierDefaultApp/OWNERS +++ b/packages/CarrierDefaultApp/OWNERS @@ -2,17 +2,16 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com -amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com satk@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java index 5252c6c82754..52d243a14e2f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java @@ -20,9 +20,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.shadow.api.Shadow.extract; -import android.net.ConnectivityManager; import android.os.UserManager; -import android.util.SparseBooleanArray; +import android.telephony.TelephonyManager; import org.junit.Before; import org.junit.Test; @@ -35,7 +34,7 @@ import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) @Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class, - SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class}) + SimStatusImeiInfoPreferenceControllerTest.ShadowTelephonyManager.class}) public class SimStatusImeiInfoPreferenceControllerTest { private AbstractSimStatusImeiInfoPreferenceController mController; @@ -56,9 +55,9 @@ public class SimStatusImeiInfoPreferenceControllerTest { ShadowUserManager userManager = extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); userManager.setIsAdminUser(true); - ShadowConnectivityManager connectivityManager = - extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true); + ShadowTelephonyManager telephonyManager = + extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class)); + telephonyManager.setDataCapable(true); assertThat(mController.isAvailable()).isTrue(); } @@ -68,9 +67,9 @@ public class SimStatusImeiInfoPreferenceControllerTest { ShadowUserManager userManager = extract(RuntimeEnvironment.application.getSystemService(UserManager.class)); userManager.setIsAdminUser(true); - ShadowConnectivityManager connectivityManager = - extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); + ShadowTelephonyManager telephonyManager = + extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class)); + telephonyManager.setDataCapable(false); assertThat(mController.isAvailable()).isFalse(); } @@ -99,19 +98,17 @@ public class SimStatusImeiInfoPreferenceControllerTest { } } - @Implements(ConnectivityManager.class) - public static class ShadowConnectivityManager - extends org.robolectric.shadows.ShadowConnectivityManager { - - private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray(); - - private void setNetworkSupported(int networkType, boolean supported) { - mSupportedNetworkTypes.put(networkType, supported); + @Implements(TelephonyManager.class) + public static class ShadowTelephonyManager + extends org.robolectric.shadows.ShadowTelephonyManager { + private boolean mDataCapable = false; + private void setDataCapable(boolean capable) { + mDataCapable = capable; } @Implementation - public boolean isNetworkSupported(int networkType) { - return mSupportedNetworkTypes.get(networkType); + public boolean isDataCapable() { + return mDataCapable; } } } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 54fb6475197a..76b0b385dbda 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -641,6 +641,15 @@ </intent-filter> </receiver> + <receiver + android:name=".ProfcollectUploadReceiver" + android:exported="true" + android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" > + <intent-filter> + <action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" /> + </intent-filter> + </receiver> + <service android:name=".BugreportProgressService" android:exported="false"/> diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml index 225c7571e7e2..85d7dd372294 100644 --- a/packages/Shell/res/xml/file_provider_paths.xml +++ b/packages/Shell/res/xml/file_provider_paths.xml @@ -1,3 +1,4 @@ <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="bugreports" path="bugreports/" /> + <root-path name="profcollect" path="/data/misc/profcollectd/report/" /> </paths> diff --git a/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java new file mode 100644 index 000000000000..d2da724796cb --- /dev/null +++ b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 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.shell; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.util.Log; + +import androidx.core.content.FileProvider; + +import com.android.internal.R; + +import java.io.File; +import java.util.List; + +/** + * A proxy service that relays report upload requests to the uploader app, while translating + * the path to the report to a content URI owned by this service. + */ +public final class ProfcollectUploadReceiver extends BroadcastReceiver { + private static final String AUTHORITY = "com.android.shell"; + private static final String PROFCOLLECT_DATA_ROOT = "/data/misc/profcollectd/report/"; + + private static final String LOG_TAG = "ProfcollectUploadReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + Log.i(LOG_TAG, "Received upload intent"); + + String uploaderPkg = getUploaderPackageName(context); + String uploaderAction = getUploaderActionName(context); + + try { + ApplicationInfo info = context.getPackageManager().getApplicationInfo(uploaderPkg, + 0); + if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + Log.e(LOG_TAG, "The profcollect uploader app " + uploaderPkg + + " must be a system application"); + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(LOG_TAG, "Cannot find profcollect uploader app " + uploaderPkg); + return; + } + + String filename = intent.getStringExtra("filename"); + File reportFile = new File(PROFCOLLECT_DATA_ROOT + filename); + Uri reportUri = FileProvider.getUriForFile(context, AUTHORITY, reportFile); + Intent uploadIntent = + new Intent(uploaderAction) + .setPackage(uploaderPkg) + .putExtra("EXTRA_DESTINATION", "PROFCOLLECT") + .putExtra("EXTRA_PACKAGE_NAME", context.getPackageName()) + .setData(reportUri) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + + List<ResolveInfo> receivers = + context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); + if (receivers == null || receivers.isEmpty()) { + Log.e(LOG_TAG, "No one to receive upload intent, abort upload."); + return; + } + + context.grantUriPermission(uploaderPkg, reportUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.sendBroadcast(uploadIntent); + } + + private String getUploaderPackageName(Context context) { + return context.getResources().getString( + R.string.config_defaultProfcollectReportUploaderApp); + } + + private String getUploaderActionName(Context context) { + return context.getResources().getString( + R.string.config_defaultProfcollectReportUploaderAction); + } +} diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 1cf14f2362de..ce23a8bc09ca 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -22,6 +22,7 @@ hwwang@google.com hyunyoungs@google.com jaggies@google.com jamesoleary@google.com +jbolinger@google.com jdemeulenaere@google.com jeffdq@google.com jjaggi@google.com diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp new file mode 100644 index 000000000000..9a6fa8e8e423 --- /dev/null +++ b/rs/jni/Android.bp @@ -0,0 +1,54 @@ +// +// Copyright (C) 2021 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 { + // See: http://go/android-license-faq + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_library_shared { + name: "librs_jni", + + srcs: ["android_renderscript_RenderScript.cpp"], + + shared_libs: [ + "libandroid", + "libandroid_runtime", + "libandroidfw", + "libRS", + "libcutils", + "libhwui", + "liblog", + "libutils", + "libui", + "libgui", + "libjnigraphics", + ], + + header_libs: [ + "jni_headers", + "libbase_headers", + ], + + include_dirs: ["frameworks/rs"], + + cflags: [ + "-Wno-unused-parameter", + "-Wunused", + "-Wunreachable-code", + "-Wno-deprecated-declarations", + ], +} diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk deleted file mode 100644 index 0caba421dca8..000000000000 --- a/rs/jni/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - android_renderscript_RenderScript.cpp - -LOCAL_SHARED_LIBRARIES := \ - libandroid \ - libandroid_runtime \ - libandroidfw \ - libRS \ - libcutils \ - libhwui \ - liblog \ - libutils \ - libui \ - libgui \ - libjnigraphics - -LOCAL_HEADER_LIBRARIES := \ - jni_headers \ - libbase_headers - -LOCAL_C_INCLUDES += \ - frameworks/rs - -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations - -LOCAL_MODULE:= librs_jni -LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS:= notice -LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE -LOCAL_MODULE_TAGS := optional -LOCAL_REQUIRED_MODULES := libRS - -include $(BUILD_SHARED_LIBRARY) diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 0146aa82a217..728efa505d99 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -17,6 +17,7 @@ package com.android.server; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import static com.android.server.health.Utils.copy; import android.annotation.Nullable; import android.app.ActivityManager; @@ -26,13 +27,7 @@ import android.content.Context; import android.content.Intent; import android.database.ContentObserver; import android.hardware.health.V1_0.HealthInfo; -import android.hardware.health.V2_0.IHealth; -import android.hardware.health.V2_0.Result; import android.hardware.health.V2_1.BatteryCapacityLevel; -import android.hardware.health.V2_1.Constants; -import android.hardware.health.V2_1.IHealthInfoCallback; -import android.hidl.manager.V1_0.IServiceManager; -import android.hidl.manager.V1_0.IServiceNotification; import android.metrics.LogMaker; import android.os.BatteryManager; import android.os.BatteryManagerInternal; @@ -44,7 +39,6 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.FileUtils; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBatteryPropertiesRegistrar; import android.os.IBinder; import android.os.OsProtoEnums; @@ -62,15 +56,14 @@ import android.provider.Settings; import android.service.battery.BatteryServiceDumpProto; import android.sysprop.PowerProperties; import android.util.EventLog; -import android.util.MutableInt; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.DumpUtils; import com.android.server.am.BatteryStatsService; +import com.android.server.health.HealthServiceWrapper; import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; @@ -82,8 +75,6 @@ import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; /** * <p>BatteryService monitors the charging status, and charge level of the device @@ -191,7 +182,6 @@ public final class BatteryService extends SystemService { private ActivityManagerInternal mActivityManagerInternal; private HealthServiceWrapper mHealthServiceWrapper; - private HealthHalCallback mHealthHalCallback; private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar; private ArrayDeque<Bundle> mBatteryLevelsEventQueue; private long mLastBatteryLevelChangedSentMs; @@ -274,13 +264,9 @@ public final class BatteryService extends SystemService { private void registerHealthCallback() { traceBegin("HealthInitWrapper"); - mHealthServiceWrapper = new HealthServiceWrapper(); - mHealthHalCallback = new HealthHalCallback(); // IHealth is lazily retrieved. try { - mHealthServiceWrapper.init(mHealthHalCallback, - new HealthServiceWrapper.IServiceManagerSupplier() {}, - new HealthServiceWrapper.IHealthSupplier() {}); + mHealthServiceWrapper = HealthServiceWrapper.create(this::update); } catch (RemoteException ex) { Slog.e(TAG, "health: cannot register callback. (RemoteException)"); throw ex.rethrowFromSystemServer(); @@ -454,25 +440,6 @@ public final class BatteryService extends SystemService { traceEnd(); } - private static void copy(HealthInfo dst, HealthInfo src) { - dst.chargerAcOnline = src.chargerAcOnline; - dst.chargerUsbOnline = src.chargerUsbOnline; - dst.chargerWirelessOnline = src.chargerWirelessOnline; - dst.maxChargingCurrent = src.maxChargingCurrent; - dst.maxChargingVoltage = src.maxChargingVoltage; - dst.batteryStatus = src.batteryStatus; - dst.batteryHealth = src.batteryHealth; - dst.batteryPresent = src.batteryPresent; - dst.batteryLevel = src.batteryLevel; - dst.batteryVoltage = src.batteryVoltage; - dst.batteryTemperature = src.batteryTemperature; - dst.batteryCurrent = src.batteryCurrent; - dst.batteryCycleCount = src.batteryCycleCount; - dst.batteryFullCharge = src.batteryFullCharge; - dst.batteryChargeCounter = src.batteryChargeCounter; - dst.batteryTechnology = src.batteryTechnology; - } - private static int plugType(HealthInfo healthInfo) { if (healthInfo.chargerAcOnline) { return BatteryManager.BATTERY_PLUGGED_AC; @@ -1184,64 +1151,6 @@ public final class BatteryService extends SystemService { } } - private final class HealthHalCallback extends IHealthInfoCallback.Stub - implements HealthServiceWrapper.Callback { - @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) { - android.hardware.health.V2_1.HealthInfo propsLatest = - new android.hardware.health.V2_1.HealthInfo(); - propsLatest.legacy = props; - - propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED; - propsLatest.batteryChargeTimeToFullNowSeconds = - Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED; - - BatteryService.this.update(propsLatest); - } - - @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) { - BatteryService.this.update(props); - } - - // on new service registered - @Override public void onRegistration(IHealth oldService, IHealth newService, - String instance) { - if (newService == null) return; - - traceBegin("HealthUnregisterCallback"); - try { - if (oldService != null) { - int r = oldService.unregisterCallback(this); - if (r != Result.SUCCESS) { - Slog.w(TAG, "health: cannot unregister previous callback: " + - Result.toString(r)); - } - } - } catch (RemoteException ex) { - Slog.w(TAG, "health: cannot unregister previous callback (transaction error): " - + ex.getMessage()); - } finally { - traceEnd(); - } - - traceBegin("HealthRegisterCallback"); - try { - int r = newService.registerCallback(this); - if (r != Result.SUCCESS) { - Slog.w(TAG, "health: cannot register callback: " + Result.toString(r)); - return; - } - // registerCallback does NOT guarantee that update is called - // immediately, so request a manual update here. - newService.update(); - } catch (RemoteException ex) { - Slog.e(TAG, "health: cannot register callback (transaction error): " - + ex.getMessage()); - } finally { - traceEnd(); - } - } - } - private final class BinderService extends Binder { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -1265,71 +1174,11 @@ public final class BatteryService extends SystemService { private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub { @Override public int getProperty(int id, final BatteryProperty prop) throws RemoteException { - traceBegin("HealthGetProperty"); - try { - IHealth service = mHealthServiceWrapper.getLastService(); - if (service == null) throw new RemoteException("no health service"); - final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED); - switch(id) { - case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER: - service.getChargeCounter((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW: - service.getCurrentNow((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE: - service.getCurrentAverage((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_CAPACITY: - service.getCapacity((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_STATUS: - service.getChargeStatus((int result, int value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER: - service.getEnergyCounter((int result, long value) -> { - outResult.value = result; - if (result == Result.SUCCESS) prop.setLong(value); - }); - break; - } - return outResult.value; - } finally { - traceEnd(); - } + return mHealthServiceWrapper.getProperty(id, prop); } @Override public void scheduleUpdate() throws RemoteException { - mHealthServiceWrapper.getHandlerThread().getThreadHandler().post(() -> { - traceBegin("HealthScheduleUpdate"); - try { - IHealth service = mHealthServiceWrapper.getLastService(); - if (service == null) { - Slog.e(TAG, "no health service"); - return; - } - service.update(); - } catch (RemoteException ex) { - Slog.e(TAG, "Cannot call update on health HAL", ex); - } finally { - traceEnd(); - } - }); + mHealthServiceWrapper.scheduleUpdate(); } } @@ -1418,184 +1267,4 @@ public final class BatteryService extends SystemService { BatteryService.this.suspendBatteryInput(); } } - - /** - * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when - * necessary. - * - * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and - * the internal service is refreshed. - * On death of an existing IHealth service, the internal service is NOT cleared to avoid - * race condition between death notification and new service notification. Hence, - * a caller must check for transaction errors when calling into the service. - * - * @hide Should only be used internally. - */ - public static final class HealthServiceWrapper { - private static final String TAG = "HealthServiceWrapper"; - public static final String INSTANCE_VENDOR = "default"; - - private final IServiceNotification mNotification = new Notification(); - private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); - // These variables are fixed after init. - private Callback mCallback; - private IHealthSupplier mHealthSupplier; - private String mInstanceName; - - // Last IHealth service received. - private final AtomicReference<IHealth> mLastService = new AtomicReference<>(); - - /** - * init should be called after constructor. For testing purposes, init is not called by - * constructor. - */ - public HealthServiceWrapper() { - } - - public IHealth getLastService() { - return mLastService.get(); - } - - /** - * See {@link #init(Callback, IServiceManagerSupplier, IHealthSupplier)} - */ - public void init() throws RemoteException, NoSuchElementException { - init(/* callback= */null, new HealthServiceWrapper.IServiceManagerSupplier() {}, - new HealthServiceWrapper.IHealthSupplier() {}); - } - - /** - * Start monitoring registration of new IHealth services. Only instance - * {@link #INSTANCE_VENDOR} and in device / framework manifest are used. This function should - * only be called once. - * - * mCallback.onRegistration() is called synchronously (aka in init thread) before - * this method returns if callback is not null. - * - * @throws RemoteException transaction error when talking to IServiceManager - * @throws NoSuchElementException if one of the following cases: - * - No service manager; - * - {@link #INSTANCE_VENDOR} is not in manifests (i.e. not - * available on this device), or none of these instances are available to current - * process. - * @throws NullPointerException when supplier is null - */ - void init(@Nullable Callback callback, - IServiceManagerSupplier managerSupplier, - IHealthSupplier healthSupplier) - throws RemoteException, NoSuchElementException, NullPointerException { - if (managerSupplier == null || healthSupplier == null) { - throw new NullPointerException(); - } - IServiceManager manager; - - mHealthSupplier = healthSupplier; - - // Initialize mLastService and call callback for the first time (in init thread) - IHealth newService = null; - traceBegin("HealthInitGetService_" + INSTANCE_VENDOR); - try { - newService = healthSupplier.get(INSTANCE_VENDOR); - } catch (NoSuchElementException ex) { - /* ignored, handled below */ - } finally { - traceEnd(); - } - if (newService != null) { - mInstanceName = INSTANCE_VENDOR; - mLastService.set(newService); - } - - if (mInstanceName == null || newService == null) { - throw new NoSuchElementException(String.format( - "IHealth service instance %s isn't available. Perhaps no permission?", - INSTANCE_VENDOR)); - } - - if (callback != null) { - mCallback = callback; - mCallback.onRegistration(null, newService, mInstanceName); - } - - // Register for future service registrations - traceBegin("HealthInitRegisterNotification"); - mHandlerThread.start(); - try { - managerSupplier.get().registerForNotifications( - IHealth.kInterfaceName, mInstanceName, mNotification); - } finally { - traceEnd(); - } - Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName); - } - - @VisibleForTesting - HandlerThread getHandlerThread() { - return mHandlerThread; - } - - interface Callback { - /** - * This function is invoked asynchronously when a new and related IServiceNotification - * is received. - * @param service the recently retrieved service from IServiceManager. - * Can be a dead service before service notification of a new service is delivered. - * Implementation must handle cases for {@link RemoteException}s when calling - * into service. - * @param instance instance name. - */ - void onRegistration(IHealth oldService, IHealth newService, String instance); - } - - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IServiceManagerSupplier { - default IServiceManager get() throws NoSuchElementException, RemoteException { - return IServiceManager.getService(); - } - } - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IHealthSupplier { - default IHealth get(String name) throws NoSuchElementException, RemoteException { - return IHealth.getService(name, true /* retry */); - } - } - - private class Notification extends IServiceNotification.Stub { - @Override - public final void onRegistration(String interfaceName, String instanceName, - boolean preexisting) { - if (!IHealth.kInterfaceName.equals(interfaceName)) return; - if (!mInstanceName.equals(instanceName)) return; - - // This runnable only runs on mHandlerThread and ordering is ensured, hence - // no locking is needed inside the runnable. - mHandlerThread.getThreadHandler().post(new Runnable() { - @Override - public void run() { - try { - IHealth newService = mHealthSupplier.get(mInstanceName); - IHealth oldService = mLastService.getAndSet(newService); - - // preexisting may be inaccurate (race). Check for equality here. - if (Objects.equals(newService, oldService)) return; - - Slog.i(TAG, "health: new instance registered " + mInstanceName); - // #init() may be called with null callback. Skip null callbacks. - if (mCallback == null) return; - mCallback.onRegistration(oldService, newService, mInstanceName); - } catch (NoSuchElementException | RemoteException ex) { - Slog.e(TAG, "health: Cannot get instance '" + mInstanceName - + "': " + ex.getMessage() + ". Perhaps no permission?"); - } - } - }); - } - } - } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c74270882260..5ed6c86bdc18 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -47,6 +47,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import android.telecom.TelecomManager; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; @@ -1960,42 +1961,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { ApnSetting apnSetting = preciseState.getApnSetting(); - int apnTypes = apnSetting.getApnTypeBitmask(); - int state = preciseState.getState(); - int networkType = preciseState.getNetworkType(); - synchronized (mRecords) { if (validatePhoneId(phoneId)) { - // We only call the callback when the change is for default APN type. - if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0 - && (mDataConnectionState[phoneId] != state - || mDataConnectionNetworkType[phoneId] != networkType)) { - String str = "onDataConnectionStateChanged(" - + TelephonyUtils.dataStateToString(state) - + ", " + getNetworkTypeName(networkType) - + ") subId=" + subId + ", phoneId=" + phoneId; - log(str); - mLocalLog.log(str); - for (Record r : mRecords) { - if (r.matchTelephonyCallbackEvent( - TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r, subId, phoneId)) { - try { - if (DBG) { - log("Notify data connection state changed on sub: " + subId); - } - r.callback.onDataConnectionStateChanged(state, networkType); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); - } - } - } - handleRemoveListLocked(); - - mDataConnectionState[phoneId] = state; - mDataConnectionNetworkType[phoneId] = networkType; - } - Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(), preciseState.getApnSetting()); PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId) @@ -2027,6 +1994,73 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) { mPreciseDataConnectionStates.get(phoneId).put(key, preciseState); } + + // Note that below is just the workaround for reporting the correct data connection + // state. The actual fix should be put in the new data stack in T. + // TODO: Remove the code below in T. + + // Collect all possible candidate data connection state for internet. Key is the + // data connection state, value is the precise data connection state. + Map<Integer, PreciseDataConnectionState> internetConnections = new ArrayMap<>(); + if (preciseState.getState() == TelephonyManager.DATA_DISCONNECTED + && preciseState.getApnSetting().getApnTypes() + .contains(ApnSetting.TYPE_DEFAULT)) { + internetConnections.put(TelephonyManager.DATA_DISCONNECTED, preciseState); + } + for (Map.Entry<Pair<Integer, ApnSetting>, PreciseDataConnectionState> entry : + mPreciseDataConnectionStates.get(phoneId).entrySet()) { + if (entry.getKey().first == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + && entry.getKey().second.getApnTypes() + .contains(ApnSetting.TYPE_DEFAULT)) { + internetConnections.put(entry.getValue().getState(), entry.getValue()); + } + } + + // If any internet data is in connected state, then report connected, then check + // suspended, connecting, disconnecting, and disconnected. The order is very + // important. + int[] statesInPriority = new int[]{TelephonyManager.DATA_CONNECTED, + TelephonyManager.DATA_SUSPENDED, TelephonyManager.DATA_CONNECTING, + TelephonyManager.DATA_DISCONNECTING, + TelephonyManager.DATA_DISCONNECTED}; + int state = TelephonyManager.DATA_DISCONNECTED; + int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + for (int s : statesInPriority) { + if (internetConnections.containsKey(s)) { + state = s; + networkType = internetConnections.get(s).getNetworkType(); + break; + } + } + + if (mDataConnectionState[phoneId] != state + || mDataConnectionNetworkType[phoneId] != networkType) { + String str = "onDataConnectionStateChanged(" + + TelephonyUtils.dataStateToString(state) + + ", " + TelephonyManager.getNetworkTypeName(networkType) + + ") subId=" + subId + ", phoneId=" + phoneId; + log(str); + mLocalLog.log(str); + for (Record r : mRecords) { + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) + && idMatch(r, subId, phoneId)) { + try { + if (DBG) { + log("Notify data connection state changed on sub: " + subId); + } + r.callback.onDataConnectionStateChanged(state, networkType); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + + mDataConnectionState[phoneId] = state; + mDataConnectionNetworkType[phoneId] = networkType; + + handleRemoveListLocked(); + } } } } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 3ccacd84a9f3..eee21460dcb0 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -94,6 +94,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_STATSD_NATIVE, DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT, DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, + DeviceConfig.NAMESPACE_TETHERING, DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, }; diff --git a/services/core/java/com/android/server/health/HealthHalCallbackHidl.java b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java new file mode 100644 index 000000000000..6b4d7b7c17c1 --- /dev/null +++ b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 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.server.health; + +import android.annotation.NonNull; +import android.hardware.health.V2_0.IHealth; +import android.hardware.health.V2_0.Result; +import android.hardware.health.V2_1.BatteryCapacityLevel; +import android.hardware.health.V2_1.Constants; +import android.hardware.health.V2_1.IHealthInfoCallback; +import android.os.RemoteException; +import android.os.Trace; +import android.util.Slog; + +/** + * On service registration, {@link HealthServiceWrapperHidl.Callback#onRegistration} is called, + * which registers {@code this}, a {@link IHealthInfoCallback}, to the health service. + * + * <p>When the health service has updates to health info, {@link HealthInfoCallback#update} is + * called. + * + * @hide + */ +class HealthHalCallbackHidl extends IHealthInfoCallback.Stub + implements HealthServiceWrapperHidl.Callback { + + private static final String TAG = HealthHalCallbackHidl.class.getSimpleName(); + + private static void traceBegin(String name) { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); + } + + private static void traceEnd() { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + + private HealthInfoCallback mCallback; + + HealthHalCallbackHidl(@NonNull HealthInfoCallback callback) { + mCallback = callback; + } + + @Override + public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) { + android.hardware.health.V2_1.HealthInfo propsLatest = + new android.hardware.health.V2_1.HealthInfo(); + propsLatest.legacy = props; + + propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED; + propsLatest.batteryChargeTimeToFullNowSeconds = + Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED; + + mCallback.update(propsLatest); + } + + @Override + public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) { + mCallback.update(props); + } + + // on new service registered + @Override + public void onRegistration(IHealth oldService, IHealth newService, String instance) { + if (newService == null) return; + + traceBegin("HealthUnregisterCallback"); + try { + if (oldService != null) { + int r = oldService.unregisterCallback(this); + if (r != Result.SUCCESS) { + Slog.w( + TAG, + "health: cannot unregister previous callback: " + Result.toString(r)); + } + } + } catch (RemoteException ex) { + Slog.w( + TAG, + "health: cannot unregister previous callback (transaction error): " + + ex.getMessage()); + } finally { + traceEnd(); + } + + traceBegin("HealthRegisterCallback"); + try { + int r = newService.registerCallback(this); + if (r != Result.SUCCESS) { + Slog.w(TAG, "health: cannot register callback: " + Result.toString(r)); + return; + } + // registerCallback does NOT guarantee that update is called + // immediately, so request a manual update here. + newService.update(); + } catch (RemoteException ex) { + Slog.e(TAG, "health: cannot register callback (transaction error): " + ex.getMessage()); + } finally { + traceEnd(); + } + } +} diff --git a/services/core/java/com/android/server/health/HealthInfoCallback.java b/services/core/java/com/android/server/health/HealthInfoCallback.java new file mode 100644 index 000000000000..8136ca0c6068 --- /dev/null +++ b/services/core/java/com/android/server/health/HealthInfoCallback.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 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.server.health; + +/** + * A wrapper over HIDL / AIDL IHealthInfoCallback. + * + * @hide + */ +public interface HealthInfoCallback { + /** + * Signals to the client that health info is changed. + * + * @param props the new health info. + */ + // TODO(b/177269435): AIDL + void update(android.hardware.health.V2_1.HealthInfo props); +} diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java new file mode 100644 index 000000000000..0b43f26e294d --- /dev/null +++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 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.server.health; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.BatteryProperty; +import android.os.HandlerThread; +import android.os.IBatteryPropertiesRegistrar; +import android.os.RemoteException; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.NoSuchElementException; + +/** + * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when necessary. + * This is essentially a wrapper over IHealth that is useful for BatteryService. + * + * <p>The implementation may be backed by a HIDL or AIDL HAL. + * + * <p>On new registration of IHealth service, the internal service is refreshed. On death of an + * existing IHealth service, the internal service is NOT cleared to avoid race condition between + * death notification and new service notification. Hence, a caller must check for transaction + * errors when calling into the service. + * + * @hide Should only be used internally. + */ +public abstract class HealthServiceWrapper { + /** @return the handler thread. Exposed for testing. */ + @VisibleForTesting + abstract HandlerThread getHandlerThread(); + + /** + * Calls into get*() functions in the health HAL. This reads into the kernel interfaces + * directly. + * + * @see IBatteryPropertiesRegistrar#getProperty + */ + public abstract int getProperty(int id, BatteryProperty prop) throws RemoteException; + + /** + * Calls update() in the health HAL. + * + * @see IBatteryPropertiesRegistrar#scheduleUpdate + */ + public abstract void scheduleUpdate() throws RemoteException; + + /** + * Calls into getHealthInfo() in the health HAL. This returns a cached value in the health HAL + * implementation. + * + * @return health info. {@code null} if no health HAL service. {@code null} if any + * service-specific error when calling {@code getHealthInfo}, e.g. it is unsupported. + * @throws RemoteException for any transaction-level errors + */ + // TODO(b/177269435): AIDL + public abstract android.hardware.health.V1_0.HealthInfo getHealthInfo() throws RemoteException; + + /** + * Create a new HealthServiceWrapper instance. + * + * @param healthInfoCallback the callback to call when health info changes + * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service. + * @throws RemoteException transaction errors + * @throws NoSuchElementException no HIDL or AIDL service is available + */ + public static HealthServiceWrapper create(@Nullable HealthInfoCallback healthInfoCallback) + throws RemoteException, NoSuchElementException { + return create( + healthInfoCallback == null ? null : new HealthHalCallbackHidl(healthInfoCallback), + new HealthServiceWrapperHidl.IServiceManagerSupplier() {}, + new HealthServiceWrapperHidl.IHealthSupplier() {}); + } + + /** + * Create a new HealthServiceWrapper instance for testing. + * + * @param hidlRegCallback callback for HIDL service registration, or {@code null} if the client + * does not care about HIDL service registration notifications + * @param hidlServiceManagerSupplier supplier of HIDL service manager + * @param hidlHealthSupplier supplier of HIDL health HAL + * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service. + */ + @VisibleForTesting + static @NonNull HealthServiceWrapper create( + @Nullable HealthServiceWrapperHidl.Callback hidlRegCallback, + @NonNull HealthServiceWrapperHidl.IServiceManagerSupplier hidlServiceManagerSupplier, + @NonNull HealthServiceWrapperHidl.IHealthSupplier hidlHealthSupplier) + throws RemoteException, NoSuchElementException { + return new HealthServiceWrapperHidl( + hidlRegCallback, hidlServiceManagerSupplier, hidlHealthSupplier); + } +} diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java new file mode 100644 index 000000000000..3bff2f83d3d2 --- /dev/null +++ b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2021 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.server.health; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.health.V1_0.HealthInfo; +import android.hardware.health.V2_0.IHealth; +import android.hardware.health.V2_0.Result; +import android.hidl.manager.V1_0.IServiceManager; +import android.hidl.manager.V1_0.IServiceNotification; +import android.os.BatteryManager; +import android.os.BatteryProperty; +import android.os.HandlerThread; +import android.os.RemoteException; +import android.os.Trace; +import android.util.MutableInt; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Implement {@link HealthServiceWrapper} backed by the HIDL HAL. + * + * @hide + */ +final class HealthServiceWrapperHidl extends HealthServiceWrapper { + private static final String TAG = "HealthServiceWrapperHidl"; + public static final String INSTANCE_VENDOR = "default"; + + private final IServiceNotification mNotification = new Notification(); + private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); + // These variables are fixed after init. + private Callback mCallback; + private IHealthSupplier mHealthSupplier; + private String mInstanceName; + + // Last IHealth service received. + private final AtomicReference<IHealth> mLastService = new AtomicReference<>(); + + private static void traceBegin(String name) { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); + } + + private static void traceEnd() { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + + @Override + public int getProperty(int id, final BatteryProperty prop) throws RemoteException { + traceBegin("HealthGetProperty"); + try { + IHealth service = mLastService.get(); + if (service == null) throw new RemoteException("no health service"); + final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED); + switch (id) { + case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER: + service.getChargeCounter( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW: + service.getCurrentNow( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE: + service.getCurrentAverage( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_CAPACITY: + service.getCapacity( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_STATUS: + service.getChargeStatus( + (int result, int value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER: + service.getEnergyCounter( + (int result, long value) -> { + outResult.value = result; + if (result == Result.SUCCESS) prop.setLong(value); + }); + break; + } + return outResult.value; + } finally { + traceEnd(); + } + } + + @Override + public void scheduleUpdate() throws RemoteException { + getHandlerThread() + .getThreadHandler() + .post( + () -> { + traceBegin("HealthScheduleUpdate"); + try { + IHealth service = mLastService.get(); + if (service == null) { + Slog.e(TAG, "no health service"); + return; + } + service.update(); + } catch (RemoteException ex) { + Slog.e(TAG, "Cannot call update on health HAL", ex); + } finally { + traceEnd(); + } + }); + } + + private static class Mutable<T> { + public T value; + } + + @Override + public HealthInfo getHealthInfo() throws RemoteException { + IHealth service = mLastService.get(); + if (service == null) return null; + final Mutable<HealthInfo> ret = new Mutable<>(); + service.getHealthInfo( + (result, value) -> { + if (result == Result.SUCCESS) { + ret.value = value.legacy; + } + }); + return ret.value; + } + + /** + * Start monitoring registration of new IHealth services. Only instance {@link #INSTANCE_VENDOR} + * and in device / framework manifest are used. This function should only be called once. + * + * <p>mCallback.onRegistration() is called synchronously (aka in init thread) before this method + * returns if callback is not null. + * + * @throws RemoteException transaction error when talking to IServiceManager + * @throws NoSuchElementException if one of the following cases: - No service manager; - {@link + * #INSTANCE_VENDOR} is not in manifests (i.e. not available on this device), or none of + * these instances are available to current process. + * @throws NullPointerException when supplier is null + */ + @VisibleForTesting + HealthServiceWrapperHidl( + @Nullable Callback callback, + @NonNull IServiceManagerSupplier managerSupplier, + @NonNull IHealthSupplier healthSupplier) + throws RemoteException, NoSuchElementException, NullPointerException { + if (managerSupplier == null || healthSupplier == null) { + throw new NullPointerException(); + } + mHealthSupplier = healthSupplier; + + // Initialize mLastService and call callback for the first time (in init thread) + IHealth newService = null; + traceBegin("HealthInitGetService_" + INSTANCE_VENDOR); + try { + newService = healthSupplier.get(INSTANCE_VENDOR); + } catch (NoSuchElementException ex) { + /* ignored, handled below */ + } finally { + traceEnd(); + } + if (newService != null) { + mInstanceName = INSTANCE_VENDOR; + mLastService.set(newService); + } + + if (mInstanceName == null || newService == null) { + throw new NoSuchElementException( + String.format( + "IHealth service instance %s isn't available. Perhaps no permission?", + INSTANCE_VENDOR)); + } + + if (callback != null) { + mCallback = callback; + mCallback.onRegistration(null, newService, mInstanceName); + } + + // Register for future service registrations + traceBegin("HealthInitRegisterNotification"); + mHandlerThread.start(); + try { + managerSupplier + .get() + .registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification); + } finally { + traceEnd(); + } + Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName); + } + + @VisibleForTesting + public HandlerThread getHandlerThread() { + return mHandlerThread; + } + + /** Service registration callback. */ + interface Callback { + /** + * This function is invoked asynchronously when a new and related IServiceNotification is + * received. + * + * @param service the recently retrieved service from IServiceManager. Can be a dead service + * before service notification of a new service is delivered. Implementation must handle + * cases for {@link RemoteException}s when calling into service. + * @param instance instance name. + */ + void onRegistration(IHealth oldService, IHealth newService, String instance); + } + + /** + * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service + * is not available. + */ + interface IServiceManagerSupplier { + default IServiceManager get() throws NoSuchElementException, RemoteException { + return IServiceManager.getService(); + } + } + + /** + * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service + * is not available. + */ + interface IHealthSupplier { + default IHealth get(String name) throws NoSuchElementException, RemoteException { + return IHealth.getService(name, true /* retry */); + } + } + + private class Notification extends IServiceNotification.Stub { + @Override + public final void onRegistration( + String interfaceName, String instanceName, boolean preexisting) { + if (!IHealth.kInterfaceName.equals(interfaceName)) return; + if (!mInstanceName.equals(instanceName)) return; + + // This runnable only runs on mHandlerThread and ordering is ensured, hence + // no locking is needed inside the runnable. + mHandlerThread + .getThreadHandler() + .post( + new Runnable() { + @Override + public void run() { + try { + IHealth newService = mHealthSupplier.get(mInstanceName); + IHealth oldService = mLastService.getAndSet(newService); + + // preexisting may be inaccurate (race). Check for equality + // here. + if (Objects.equals(newService, oldService)) return; + + Slog.i( + TAG, + "health: new instance registered " + mInstanceName); + // #init() may be called with null callback. Skip null + // callbacks. + if (mCallback == null) return; + mCallback.onRegistration( + oldService, newService, mInstanceName); + } catch (NoSuchElementException | RemoteException ex) { + Slog.e( + TAG, + "health: Cannot get instance '" + + mInstanceName + + "': " + + ex.getMessage() + + ". Perhaps no permission?"); + } + } + }); + } + } +} diff --git a/services/core/java/com/android/server/health/Utils.java b/services/core/java/com/android/server/health/Utils.java new file mode 100644 index 000000000000..fc039eb54950 --- /dev/null +++ b/services/core/java/com/android/server/health/Utils.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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.server.health; + +/** + * Utils for {@link om.android.server.BatteryService} to deal with health info structs. + * + * @hide + */ +public class Utils { + private Utils() {} + + /** + * Copy health info struct. + * + * @param dst destination + * @param src source + */ + public static void copy( + android.hardware.health.V1_0.HealthInfo dst, + android.hardware.health.V1_0.HealthInfo src) { + dst.chargerAcOnline = src.chargerAcOnline; + dst.chargerUsbOnline = src.chargerUsbOnline; + dst.chargerWirelessOnline = src.chargerWirelessOnline; + dst.maxChargingCurrent = src.maxChargingCurrent; + dst.maxChargingVoltage = src.maxChargingVoltage; + dst.batteryStatus = src.batteryStatus; + dst.batteryHealth = src.batteryHealth; + dst.batteryPresent = src.batteryPresent; + dst.batteryLevel = src.batteryLevel; + dst.batteryVoltage = src.batteryVoltage; + dst.batteryTemperature = src.batteryTemperature; + dst.batteryCurrent = src.batteryCurrent; + dst.batteryCycleCount = src.batteryCycleCount; + dst.batteryFullCharge = src.batteryFullCharge; + dst.batteryChargeCounter = src.batteryChargeCounter; + dst.batteryTechnology = src.batteryTechnology; + } +} diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 68b760a1be34..e6fed88a8a4a 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -92,7 +92,6 @@ import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.health.V2_0.IHealth; import android.net.ConnectivityManager; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -190,13 +189,13 @@ import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThrea import com.android.internal.util.CollectionUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.role.RoleManagerLocal; -import com.android.server.BatteryService; import com.android.server.BinderCallsStatsService; import com.android.server.LocalManagerRegistry; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; +import com.android.server.health.HealthServiceWrapper; import com.android.server.notification.NotificationManagerService; import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot; @@ -226,6 +225,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.MissingResourceException; +import java.util.NoSuchElementException; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -354,7 +354,7 @@ public class StatsPullAtomService extends SystemService { private File mBaseDir; @GuardedBy("mHealthHalLock") - private BatteryService.HealthServiceWrapper mHealthService; + private HealthServiceWrapper mHealthService; @Nullable @GuardedBy("mCpuTimePerThreadFreqLock") @@ -799,10 +799,9 @@ public class StatsPullAtomService extends SystemService { KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); // Initialize HealthService - mHealthService = new BatteryService.HealthServiceWrapper(); try { - mHealthService.init(); - } catch (RemoteException e) { + mHealthService = HealthServiceWrapper.create(null); + } catch (RemoteException | NoSuchElementException e) { Slog.e(TAG, "failed to initialize healthHalWrapper"); } @@ -3975,38 +3974,40 @@ public class StatsPullAtomService extends SystemService { } int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) { - IHealth healthService = mHealthService.getLastService(); - if (healthService == null) { + if (mHealthService == null) { return StatsManager.PULL_SKIP; } + android.hardware.health.V1_0.HealthInfo healthInfo; try { - healthService.getHealthInfo((result, value) -> { - int pulledValue; - switch(atomTag) { - case FrameworkStatsLog.BATTERY_LEVEL: - pulledValue = value.legacy.batteryLevel; - break; - case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY: - pulledValue = value.legacy.batteryChargeCounter; - break; - case FrameworkStatsLog.FULL_BATTERY_CAPACITY: - pulledValue = value.legacy.batteryFullCharge; - break; - case FrameworkStatsLog.BATTERY_VOLTAGE: - pulledValue = value.legacy.batteryVoltage; - break; - case FrameworkStatsLog.BATTERY_CYCLE_COUNT: - pulledValue = value.legacy.batteryCycleCount; - break; - default: - throw new IllegalStateException("Invalid atomTag in healthHal puller: " - + atomTag); - } - pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue)); - }); + healthInfo = mHealthService.getHealthInfo(); } catch (RemoteException | IllegalStateException e) { return StatsManager.PULL_SKIP; } + if (healthInfo == null) { + return StatsManager.PULL_SKIP; + } + + int pulledValue; + switch (atomTag) { + case FrameworkStatsLog.BATTERY_LEVEL: + pulledValue = healthInfo.batteryLevel; + break; + case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY: + pulledValue = healthInfo.batteryChargeCounter; + break; + case FrameworkStatsLog.FULL_BATTERY_CAPACITY: + pulledValue = healthInfo.batteryFullCharge; + break; + case FrameworkStatsLog.BATTERY_VOLTAGE: + pulledValue = healthInfo.batteryVoltage; + break; + case FrameworkStatsLog.BATTERY_CYCLE_COUNT: + pulledValue = healthInfo.batteryCycleCount; + break; + default: + return StatsManager.PULL_SKIP; + } + pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue)); return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 239a916fc5fc..1c46ac8c4aa1 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -98,6 +98,7 @@ import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.NetworkInterface; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -2048,7 +2049,8 @@ public class VcnGatewayConnection extends StateMachine { return builder.build(); } - private static LinkProperties buildConnectedLinkProperties( + @VisibleForTesting(visibility = Visibility.PRIVATE) + LinkProperties buildConnectedLinkProperties( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull IpSecTunnelInterface tunnelIface, @NonNull VcnChildSessionConfiguration childConfig, @@ -2076,6 +2078,13 @@ public class VcnGatewayConnection extends StateMachine { lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes()); underlyingMtu = underlyingLp.getMtu(); + + // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result + // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by + // NetworkInterface APIs. + if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) { + underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName()); + } } else { Slog.wtf( TAG, @@ -2417,6 +2426,17 @@ public class VcnGatewayConnection extends StateMachine { public long getElapsedRealTime() { return SystemClock.elapsedRealtime(); } + + /** Gets the MTU for the given underlying interface. */ + public int getUnderlyingIfaceMtu(String ifaceName) { + try { + final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName); + return underlyingIface == null ? 0 : underlyingIface.getMTU(); + } catch (IOException e) { + Slog.d(TAG, "Could not get MTU of underlying network", e); + return 0; + } + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 26c04f9487ef..d1f21778177d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -140,6 +140,7 @@ import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; +import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO; import static com.android.server.wm.ActivityRecordProto.NAME; import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; @@ -8672,6 +8673,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); + proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio()); } @Override diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index fe1020c86041..a7216da9bed5 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -190,8 +190,7 @@ class KeyguardController { if (keyguardChanged) { // Irrelevant to AOD. - dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */, - false /* turningScreenOn */); + dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */); mKeyguardGoingAway = false; if (keyguardShowing) { mDismissalRequested = false; @@ -385,6 +384,8 @@ class KeyguardController { mService.continueWindowLayout(); } } + dismissMultiWindowModeForTaskIfNeeded(topActivity != null + ? topActivity.getRootTask() : null); } /** @@ -410,21 +411,6 @@ class KeyguardController { } } - /** - * Called when somebody wants to turn screen on. - */ - private void handleTurnScreenOn(int displayId) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - - mTaskSupervisor.wakeUp("handleTurnScreenOn"); - if (mKeyguardShowing && canDismissKeyguard()) { - mWindowManager.dismissKeyguard(null /* callback */, null /* message */); - mDismissalRequested = true; - } - } - boolean isDisplayOccluded(int displayId) { return getDisplayState(displayId).mOccluded; } @@ -438,11 +424,9 @@ class KeyguardController { } private void dismissMultiWindowModeForTaskIfNeeded( - @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) { - // If turningScreenOn is true, it means that the visibility state has changed from - // currentTaskControllingOcclusion and we should update windowing mode. + @Nullable Task currentTaskControllingOcclusion) { // TODO(b/113840485): Handle docked stack for individual display. - if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) { + if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) { return; } @@ -581,26 +565,17 @@ class KeyguardController { && controller.mWindowManager.isKeyguardSecure( controller.mService.getCurrentUserId()); - boolean occludingChange = false; - boolean turningScreenOn = false; if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity && mTopTurnScreenOnActivity != null && !mService.mWindowManager.mPowerManager.isInteractive() - && (mRequestDismissKeyguard || occludedByActivity - || controller.canDismissKeyguard())) { - turningScreenOn = true; - controller.handleTurnScreenOn(mDisplayId); + && (mRequestDismissKeyguard || occludedByActivity)) { + controller.mTaskSupervisor.wakeUp("handleTurnScreenOn"); mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false); } if (lastOccluded != mOccluded) { - occludingChange = true; controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity); } - - if (occludingChange || turningScreenOn) { - controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn); - } } /** diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java index 3a9b2dca3921..cb52e5f72d5f 100644 --- a/services/java/com/android/server/SystemConfigService.java +++ b/services/java/com/android/server/SystemConfigService.java @@ -19,6 +19,7 @@ import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; import android.Manifest; +import android.content.ComponentName; import android.content.Context; import android.os.ISystemConfig; import android.util.ArrayMap; @@ -87,14 +88,14 @@ public class SystemConfigService extends SystemService { } @Override - public List<String> getEnabledComponentOverrides(String packageName) { + public List<ComponentName> getEnabledComponentOverrides(String packageName) { ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance() .getComponentsEnabledStates(packageName); - List<String> enabledComponent = new ArrayList<>(); + List<ComponentName> enabledComponent = new ArrayList<>(); if (systemComponents != null) { for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) { if (Boolean.TRUE.equals(entry.getValue())) { - enabledComponent.add(entry.getKey()); + enabledComponent.add(new ComponentName(packageName, entry.getKey())); } } } diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index fdf23d3836ac..4fb801e188d0 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -23,7 +23,6 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ResolveInfo; import android.os.Handler; import android.os.IBinder.DeathRecipient; import android.os.Looper; @@ -32,8 +31,6 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UpdateEngine; import android.os.UpdateEngineCallback; -import android.os.UserHandle; -import android.os.UserManager; import android.provider.DeviceConfig; import android.util.Log; @@ -45,9 +42,6 @@ import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; import com.android.server.wm.ActivityTaskManagerInternal; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -306,79 +300,27 @@ public final class ProfcollectForwardingService extends SystemService { return; } - if (!getUploaderEnabledConfig(getContext())) { - return; - } - + Context context = getContext(); new Thread(() -> { try { - Context context = getContext(); - final String uploaderPkg = getUploaderPackageName(context); - final String uploaderAction = getUploaderActionName(context); - String reportUuid = mIProfcollect.report(); - - final int profileId = getBBProfileId(); - String reportDir = "/data/user/" + profileId - + "/com.google.android.apps.internal.betterbug/cache/"; - String reportPath = reportDir + reportUuid + ".zip"; - - if (!Files.exists(Paths.get(reportDir))) { - Log.i(LOG_TAG, "Destination directory does not exist, abort upload."); - return; - } + // Prepare profile report + String reportName = mIProfcollect.report() + ".zip"; - Intent uploadIntent = - new Intent(uploaderAction) - .setPackage(uploaderPkg) - .putExtra("EXTRA_DESTINATION", "PROFCOLLECT") - .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName()) - .putExtra("EXTRA_PROFILE_PATH", reportPath) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - - List<ResolveInfo> receivers = - context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0); - if (receivers == null || receivers.isEmpty()) { - Log.i(LOG_TAG, "No one to receive upload intent, abort upload."); + if (!context.getResources().getBoolean( + R.bool.config_profcollectReportUploaderEnabled)) { + Log.i(LOG_TAG, "Upload is not enabled."); return; } - mIProfcollect.copy_report_to_bb(profileId, reportUuid); - context.sendBroadcast(uploadIntent); - mIProfcollect.delete_report(reportUuid); + + // Upload the report + Intent intent = new Intent() + .setPackage("com.android.shell") + .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD") + .putExtra("filename", reportName); + context.sendBroadcast(intent); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); } }).start(); } - - /** - * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system - * user ID. - * - * @return BetterBug's profile ID. - */ - private int getBBProfileId() { - UserManager userManager = UserManager.get(getContext()); - int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false); - for (int p : profiles) { - if (userManager.getUserInfo(p).isManagedProfile()) { - return p; - } - } - return UserHandle.USER_SYSTEM; - } - - private boolean getUploaderEnabledConfig(Context context) { - return context.getResources().getBoolean( - R.bool.config_profcollectReportUploaderEnabled); - } - - private String getUploaderPackageName(Context context) { - return context.getResources().getString( - R.string.config_defaultProfcollectReportUploaderApp); - } - - private String getUploaderActionName(Context context) { - return context.getResources().getString( - R.string.config_defaultProfcollectReportUploaderAction); - } } diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java index a2ecbc30ec64..c97a67bad590 100644 --- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java @@ -14,19 +14,25 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.health; -import static junit.framework.Assert.*; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.fail; import static org.mockito.Mockito.*; import android.hardware.health.V2_0.IHealth; import android.hidl.manager.V1_0.IServiceManager; import android.hidl.manager.V1_0.IServiceNotification; -import android.test.AndroidTestCase; +import android.os.RemoteException; import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -36,36 +42,39 @@ import java.util.Arrays; import java.util.Collection; import java.util.NoSuchElementException; -public class BatteryServiceTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class HealthServiceWrapperTest { @Mock IServiceManager mMockedManager; @Mock IHealth mMockedHal; @Mock IHealth mMockedHal2; - @Mock BatteryService.HealthServiceWrapper.Callback mCallback; - @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier; - @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier; - BatteryService.HealthServiceWrapper mWrapper; + @Mock HealthServiceWrapperHidl.Callback mCallback; + @Mock HealthServiceWrapperHidl.IServiceManagerSupplier mManagerSupplier; + @Mock HealthServiceWrapperHidl.IHealthSupplier mHealthServiceSupplier; + HealthServiceWrapper mWrapper; - private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR; + private static final String VENDOR = HealthServiceWrapperHidl.INSTANCE_VENDOR; - @Override + @Before public void setUp() { MockitoAnnotations.initMocks(this); } - @Override + @After public void tearDown() { - if (mWrapper != null) - mWrapper.getHandlerThread().quitSafely(); + if (mWrapper != null) mWrapper.getHandlerThread().quitSafely(); } public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) { return new ArgumentMatcher<T>() { - @Override public boolean matches(T e) { + @Override + public boolean matches(T e) { return collection.contains(e); } - @Override public String toString() { + + @Override + public String toString() { return collection.toString(); } }; @@ -73,27 +82,29 @@ public class BatteryServiceTest extends AndroidTestCase { private void initForInstances(String... instanceNamesArr) throws Exception { final Collection<String> instanceNames = Arrays.asList(instanceNamesArr); - doAnswer((invocation) -> { - // technically, preexisting is ignored by - // BatteryService.HealthServiceWrapper.Notification, but still call it correctly. - sendNotification(invocation, true); - sendNotification(invocation, true); - sendNotification(invocation, false); - return null; - }).when(mMockedManager).registerForNotifications( - eq(IHealth.kInterfaceName), - argThat(isOneOf(instanceNames)), - any(IServiceNotification.class)); + doAnswer( + (invocation) -> { + // technically, preexisting is ignored by + // HealthServiceWrapperHidl.Notification, but still call it correctly. + sendNotification(invocation, true); + sendNotification(invocation, true); + sendNotification(invocation, false); + return null; + }) + .when(mMockedManager) + .registerForNotifications( + eq(IHealth.kInterfaceName), + argThat(isOneOf(instanceNames)), + any(IServiceNotification.class)); doReturn(mMockedManager).when(mManagerSupplier).get(); - doReturn(mMockedHal) // init calls this - .doReturn(mMockedHal) // notification 1 - .doReturn(mMockedHal) // notification 2 - .doReturn(mMockedHal2) // notification 3 - .doThrow(new RuntimeException("Should not call getService for more than 4 times")) - .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames))); - - mWrapper = new BatteryService.HealthServiceWrapper(); + doReturn(mMockedHal) // init calls this + .doReturn(mMockedHal) // notification 1 + .doReturn(mMockedHal) // notification 2 + .doReturn(mMockedHal2) // notification 3 + .doThrow(new RuntimeException("Should not call getService for more than 4 times")) + .when(mHealthServiceSupplier) + .get(argThat(isOneOf(instanceNames))); } private void waitHandlerThreadFinish() throws Exception { @@ -108,16 +119,20 @@ public class BatteryServiceTest extends AndroidTestCase { private static void sendNotification(InvocationOnMock invocation, boolean preexisting) throws Exception { - ((IServiceNotification)invocation.getArguments()[2]).onRegistration( - IHealth.kInterfaceName, - (String)invocation.getArguments()[1], - preexisting); + ((IServiceNotification) invocation.getArguments()[2]) + .onRegistration( + IHealth.kInterfaceName, (String) invocation.getArguments()[1], preexisting); + } + + private void createWrapper() throws RemoteException { + mWrapper = HealthServiceWrapper.create(mCallback, mManagerSupplier, mHealthServiceSupplier); } @SmallTest + @Test public void testWrapPreferVendor() throws Exception { initForInstances(VENDOR); - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); + createWrapper(); waitHandlerThreadFinish(); verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR)); verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString()); @@ -125,10 +140,11 @@ public class BatteryServiceTest extends AndroidTestCase { } @SmallTest + @Test public void testNoService() throws Exception { initForInstances("unrelated"); try { - mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier); + createWrapper(); fail("Expect NoSuchElementException"); } catch (NoSuchElementException ex) { // expected diff --git a/services/tests/servicestests/src/com/android/server/health/OWNERS b/services/tests/servicestests/src/com/android/server/health/OWNERS new file mode 100644 index 000000000000..81522fcaa09f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/health/OWNERS @@ -0,0 +1 @@ +file:platform/hardware/interfaces:/health/aidl/OWNERS diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java index b4fbf5fe40eb..184ea521e828 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java @@ -110,18 +110,20 @@ public class ActivityOptionsTest { @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { - t.setVisibility(leash, true /* visible */).apply(); + t.show(leash).apply(); } int cookieIndex = -1; if (trampoline.equals(taskInfo.baseActivity)) { cookieIndex = 0; } else if (main.equals(taskInfo.baseActivity)) { cookieIndex = 1; - mainLatch.countDown(); } if (cookieIndex >= 0) { appearedCookies[cookieIndex] = taskInfo.launchCookies.isEmpty() ? null : taskInfo.launchCookies.get(0); + if (cookieIndex == 1) { + mainLatch.countDown(); + } } } }; diff --git a/telephony/OWNERS b/telephony/OWNERS index 4df8a4bc6413..4016ba7de379 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -1,6 +1,5 @@ set noparent -amitmahajan@google.com breadley@google.com fionaxu@google.com jackyu@google.com @@ -8,10 +7,10 @@ rgreenwalt@google.com tgunn@google.com jminjie@google.com shuoq@google.com -nazaninb@google.com sarahchin@google.com xiaotonj@google.com huiwang@google.com jayachandranc@google.com chinmayd@google.com amruthr@google.com +sasindran@google.com diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index d11c66702d99..73a308200657 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -5191,6 +5192,16 @@ public class CarrierConfigManager { "display_no_data_notification_on_permanent_failure_bool"; /** + * Boolean indicating if the VoNR setting is visible in the Call Settings menu. + * If true, the VoNR setting menu will be visible. If false, the menu will be gone. + * + * Disabled by default. + * + * @hide + */ + public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool"; + + /** * Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes * * @hide @@ -5806,6 +5817,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, ""); sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false); sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); + sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false); } /** @@ -5874,12 +5886,15 @@ public class CarrierConfigManager { * any carrier specific configuration has been applied. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}. * @return A {@link PersistableBundle} containing the config for the given subId, or default * values for an invalid subId. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfigForSubId(int subId) { try { @@ -5968,10 +5983,13 @@ public class CarrierConfigManager { * called to confirm whether any carrier specific configuration has been applied. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @see #getConfigForSubId */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfig() { return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId()); @@ -5980,8 +5998,8 @@ public class CarrierConfigManager { /** * Determines whether a configuration {@link PersistableBundle} obtained from * {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier. - * <p> - * When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} + * + * <p>When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} * broadcast which informs it that the carrier configuration has changed, it is possible * that another reload of the carrier configuration has begun since the intent was sent. * In this case, the carrier configuration the app fetches (e.g. via {@link #getConfig()}) @@ -5990,14 +6008,12 @@ public class CarrierConfigManager { * return true because it may belong to another previous identified carrier. Users should * always call {@link #getConfig()} or {@link #getConfigForSubId(int)} after receiving the * broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED}. - * </p> - * <p> - * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always + * + * <p>After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always * use this method to confirm whether any carrier specific configuration has been applied. * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it * still needs to get the current configuration, it must use this method to verify whether the * configuration is default or carrier overridden. - * </p> * * @param bundle the configuration bundle to be checked. * @return boolean true if any carrier specific configuration bundle has been applied, false @@ -6009,19 +6025,20 @@ public class CarrierConfigManager { /** * Calling this method triggers telephony services to fetch the current carrier configuration. - * <p> - * Normally this does not need to be called because the platform reloads config on its own. + * + * <p>Normally this does not need to be called because the platform reloads config on its own. * This should be called by a carrier service app if it wants to update config at an arbitrary * moment. - * </p> - * <p>Requires that the calling app has carrier privileges. - * <p> - * This method returns before the reload has completed, and - * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an - * arbitrary thread. - * </p> - * @see TelephonyManager#hasCarrierPrivileges + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). + * + * <p>This method returns before the reload has completed, and {@link + * android.service.carrier.CarrierService#onLoadConfig} will be called from an arbitrary thread. */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int subId) { try { ICarrierConfigLoader loader = getICarrierConfigLoader(); @@ -6037,11 +6054,10 @@ public class CarrierConfigManager { } /** - * Request the carrier config loader to update the cofig for phoneId. - * <p> - * Depending on simState, the config may be cleared or loaded from config app. This is only used - * by SubscriptionInfoUpdater. - * </p> + * Request the carrier config loader to update the config for phoneId. + * + * <p>Depending on simState, the config may be cleared or loaded from config app. This is only + * used by SubscriptionInfoUpdater. * * @hide */ @@ -6112,13 +6128,16 @@ public class CarrierConfigManager { * Gets the configuration values for a component using its prefix. * * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app + * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}). * * @param prefix prefix of the component. * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}. * * @see #getConfigForSubId */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) @Nullable public PersistableBundle getConfigByComponentForSubId(@NonNull String prefix, int subId) { PersistableBundle configs = getConfigForSubId(subId); diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index d250088c2f10..95448c7807cc 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -242,6 +242,11 @@ public final class PhysicalChannelConfig implements Parcelable { } /** + * The physical cell ID which differentiates cells using the same radio channel. + * + * In GERAN, this value is the BSIC. The range is [0-63]. + * Reference: 3GPP TS 3.03 section 4.2.2. + * * In UTRAN, this value is primary scrambling code. The range is [0, 511]. * Reference: 3GPP TS 25.213 section 5.2.2. * diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 122f96df4ae6..2d8c201a3e71 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -12148,6 +12148,100 @@ public class TelephonyManager { } /** + * No error. Operation succeeded. + * @hide + */ + public static final int ENABLE_VONR_SUCCESS = 0; + + /** + * Radio is not available. + * @hide + */ + public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2; + + /** + * Internal Radio error. + * @hide + */ + public static final int ENABLE_VONR_RADIO_ERROR = 3; + + /** + * Voice over NR enable/disable request is received when system is in invalid state. + * @hide + */ + public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4; + + /** + * Voice over NR enable/disable request is not supported. + * @hide + */ + public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EnableVoNrResult"}, value = { + ENABLE_VONR_SUCCESS, + ENABLE_VONR_RADIO_NOT_AVAILABLE, + ENABLE_VONR_RADIO_ERROR, + ENABLE_VONR_RADIO_INVALID_STATE, + ENABLE_VONR_REQUEST_NOT_SUPPORTED}) + public @interface EnableVoNrResult {} + + /** + * Enable or disable Voice over NR (VoNR) + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. + * + * @param enabled enable or disable VoNR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public @EnableVoNrResult int setVoNrEnabled(boolean enabled) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.setVoNrEnabled( + getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e); + } + + return ENABLE_VONR_RADIO_INVALID_STATE; + } + + /** + * Is Voice over NR (VoNR) enabled. + * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean + * voice call over NR is active or voice ove NR is available. It means the device is allowed to + * register IMS over NR. + * @throws IllegalStateException if the Telephony process is not currently available. + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isVoNrEnabled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isVoNrEnabled(getSubId()); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "isVoNrEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + return false; + } + + /** * Carrier action to start or stop reporting default network available events. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index be1502ad49f2..1ef04be8f242 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -147,7 +147,12 @@ public class ApnSetting implements Parcelable { } // Possible values for authentication types. - /** No authentication type. */ + /** + * Authentication type is unknown. + * @hide + */ + public static final int AUTH_TYPE_UNKNOWN = -1; + /** Authentication is not required. */ public static final int AUTH_TYPE_NONE = 0; /** Authentication type for PAP. */ public static final int AUTH_TYPE_PAP = 1; @@ -357,6 +362,7 @@ public class ApnSetting implements Parcelable { /** @hide */ @IntDef(prefix = { "AUTH_TYPE_" }, value = { + AUTH_TYPE_UNKNOWN, AUTH_TYPE_NONE, AUTH_TYPE_PAP, AUTH_TYPE_CHAP, @@ -498,7 +504,8 @@ public class ApnSetting implements Parcelable { private final String mOperatorNumeric; private final int mProtocol; private final int mRoamingProtocol; - private final int mMtu; + private final int mMtuV4; + private final int mMtuV6; private final boolean mCarrierEnabled; @@ -522,13 +529,25 @@ public class ApnSetting implements Parcelable { private final int mSkip464Xlat; /** - * Returns the MTU size of the mobile interface to which the APN connected. + * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * * @return the MTU size of the APN * @hide */ - public int getMtu() { - return mMtu; + public int getMtuV4() { + return mMtuV4; + } + + /** + * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @return the MTU size of the APN + * @hide + */ + public int getMtuV6() { + return mMtuV6; } /** @@ -879,13 +898,18 @@ public class ApnSetting implements Parcelable { this.mMmsProxyPort = builder.mMmsProxyPort; this.mUser = builder.mUser; this.mPassword = builder.mPassword; - this.mAuthType = builder.mAuthType; + this.mAuthType = (builder.mAuthType != AUTH_TYPE_UNKNOWN) + ? builder.mAuthType + : TextUtils.isEmpty(builder.mUser) + ? AUTH_TYPE_NONE + : AUTH_TYPE_PAP_OR_CHAP; this.mApnTypeBitmask = builder.mApnTypeBitmask; this.mId = builder.mId; this.mOperatorNumeric = builder.mOperatorNumeric; this.mProtocol = builder.mProtocol; this.mRoamingProtocol = builder.mRoamingProtocol; - this.mMtu = builder.mMtu; + this.mMtuV4 = builder.mMtuV4; + this.mMtuV6 = builder.mMtuV6; this.mCarrierEnabled = builder.mCarrierEnabled; this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask; this.mProfileId = builder.mProfileId; @@ -903,66 +927,6 @@ public class ApnSetting implements Parcelable { /** * @hide */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, - boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu, - int mvnoType, String mvnoMatchData, int apnSetId, int carrierId, int skip464xlat) { - return new Builder() - .setId(id) - .setOperatorNumeric(operatorNumeric) - .setEntryName(entryName) - .setApnName(apnName) - .setProxyAddress(proxyAddress) - .setProxyPort(proxyPort) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxyAddress) - .setMmsProxyPort(mmsProxyPort) - .setUser(user) - .setPassword(password) - .setAuthType(authType) - .setApnTypeBitmask(mApnTypeBitmask) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(carrierEnabled) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(profileId) - .setModemCognitive(modemCognitive) - .setMaxConns(maxConns) - .setWaitTime(waitTime) - .setMaxConnsTime(maxConnsTime) - .setMtu(mtu) - .setMvnoType(mvnoType) - .setMvnoMatchData(mvnoMatchData) - .setApnSetId(apnSetId) - .setCarrierId(carrierId) - .setSkip464Xlat(skip464xlat) - .buildWithoutCheck(); - } - - /** - * @hide - */ - public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName, - String apnName, String proxyAddress, int proxyPort, Uri mmsc, - String mmsProxyAddress, int mmsProxyPort, String user, String password, - int authType, int mApnTypeBitmask, int protocol, int roamingProtocol, - boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive, - int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType, - String mvnoMatchData) { - return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort, - mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId, - modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData, - Carriers.NO_APN_SET_ID, TelephonyManager.UNKNOWN_CARRIER_ID, - Carriers.SKIP_464XLAT_DEFAULT); - } - - /** - * @hide - */ public static ApnSetting makeApnSetting(Cursor cursor) { final int apnTypesBitmask = getApnTypesBitmaskFromString( cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); @@ -975,272 +939,99 @@ public class ApnSetting implements Parcelable { ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); } - return makeApnSetting( - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))), - UriFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), - cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), - portFromString(cursor.getString( - cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), - apnTypesBitmask, - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))), - getProtocolIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.ROAMING_PROTOCOL))), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.CARRIER_ENABLED)) == 1, - networkTypeBitmask, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MODEM_PERSIST)) == 1, - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)), - cursor.getInt(cursor.getColumnIndexOrThrow( - Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), - getMvnoTypeIntFromString( - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_TYPE))), - cursor.getString(cursor.getColumnIndexOrThrow( - Telephony.Carriers.MVNO_MATCH_DATA)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))); + return new Builder() + .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID))) + .setOperatorNumeric(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC))) + .setEntryName(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME))) + .setApnName(cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN))) + .setProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))) + .setProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)))) + .setMmsc(UriFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)))) + .setMmsProxyAddress(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))) + .setMmsProxyPort(portFromString(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)))) + .setUser(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.USER))) + .setPassword(cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD))) + .setAuthType(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE))) + .setApnTypeBitmask(apnTypesBitmask) + .setProtocol(getProtocolIntFromString( + cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)))) + .setRoamingProtocol(getProtocolIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.ROAMING_PROTOCOL)))) + .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.CARRIER_ENABLED)) == 1) + .setNetworkTypeBitmask(networkTypeBitmask) + .setProfileId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID))) + .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MODEM_PERSIST)) == 1) + .setMaxConns(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS))) + .setWaitTime(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY))) + .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS))) + .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU))) + .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider + .setMvnoType(getMvnoTypeIntFromString( + cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_TYPE)))) + .setMvnoMatchData(cursor.getString(cursor.getColumnIndexOrThrow( + Telephony.Carriers.MVNO_MATCH_DATA))) + .setApnSetId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID))) + .setCarrierId(cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID))) + .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT))) + .buildWithoutCheck(); } /** * @hide */ public static ApnSetting makeApnSetting(ApnSetting apn) { - return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName, - apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress, - apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask, - apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask, - apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime, - apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId, - apn.mCarrierId, apn.mSkip464Xlat); - } - - /** - * Creates an ApnSetting object from a string. - * - * @param data the string to read. - * - * The string must be in one of two formats (newlines added for clarity, - * spaces are optional): - * - * v1 format: - * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], - * - * v2 format: - * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * - * v3 format: - * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData> - * - * v4 format: - * [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask> - * - * v5 format: - * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId> - * - * v6 format: - * [ApnSettingV6] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId> - * - * v7 format: - * [ApnSettingV7] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>, - * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>, - * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>, - * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>, - * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>, <skip464xlat> - * - * Note that the strings generated by {@link #toString()} do not contain the username - * and password and thus cannot be read by this method. - * - * This method may return {@code null} if the input string is invalid. - * - * @hide - */ - public static ApnSetting fromString(String data) { - if (data == null) return null; - - int version; - // matches() operates on the whole string, so append .* to the regex. - if (data.matches(V7_FORMAT_REGEX + ".*")) { - version = 7; - data = data.replaceFirst(V7_FORMAT_REGEX, ""); - } else if (data.matches(V6_FORMAT_REGEX + ".*")) { - version = 6; - data = data.replaceFirst(V6_FORMAT_REGEX, ""); - } else if (data.matches(V5_FORMAT_REGEX + ".*")) { - version = 5; - data = data.replaceFirst(V5_FORMAT_REGEX, ""); - } else if (data.matches(V4_FORMAT_REGEX + ".*")) { - version = 4; - data = data.replaceFirst(V4_FORMAT_REGEX, ""); - } else if (data.matches(V3_FORMAT_REGEX + ".*")) { - version = 3; - data = data.replaceFirst(V3_FORMAT_REGEX, ""); - } else if (data.matches(V2_FORMAT_REGEX + ".*")) { - version = 2; - data = data.replaceFirst(V2_FORMAT_REGEX, ""); - } else { - version = 1; - } - - String[] a = data.split("\\s*,\\s*", -1); - if (a.length < 14) { - return null; - } - - int authType; - try { - authType = Integer.parseInt(a[12]); - } catch (NumberFormatException e) { - authType = 0; - } - - String[] typeArray; - String protocol, roamingProtocol; - boolean carrierEnabled; - int bearerBitmask = 0; - int networkTypeBitmask = 0; - int profileId = 0; - boolean modemCognitive = false; - int maxConns = 0; - int waitTime = 0; - int maxConnsTime = 0; - int mtu = UNSET_MTU; - String mvnoType = ""; - String mvnoMatchData = ""; - int apnSetId = Carriers.NO_APN_SET_ID; - int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; - int skip464xlat = Carriers.SKIP_464XLAT_DEFAULT; - if (version == 1) { - typeArray = new String[a.length - 13]; - System.arraycopy(a, 13, typeArray, 0, a.length - 13); - protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP); - carrierEnabled = true; - } else { - if (a.length < 18) { - return null; - } - typeArray = a[13].split("\\s*\\|\\s*"); - protocol = a[14]; - roamingProtocol = a[15]; - carrierEnabled = Boolean.parseBoolean(a[16]); - - bearerBitmask = ServiceState.getBitmaskFromString(a[17]); - - if (a.length > 22) { - modemCognitive = Boolean.parseBoolean(a[19]); - try { - profileId = Integer.parseInt(a[18]); - maxConns = Integer.parseInt(a[20]); - waitTime = Integer.parseInt(a[21]); - maxConnsTime = Integer.parseInt(a[22]); - } catch (NumberFormatException e) { - } - } - if (a.length > 23) { - try { - mtu = Integer.parseInt(a[23]); - } catch (NumberFormatException e) { - } - } - if (a.length > 25) { - mvnoType = a[24]; - mvnoMatchData = a[25]; - } - if (a.length > 26) { - networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]); - } - if (a.length > 27) { - apnSetId = Integer.parseInt(a[27]); - } - if (a.length > 28) { - carrierId = Integer.parseInt(a[28]); - } - if (a.length > 29) { - try { - skip464xlat = Integer.parseInt(a[29]); - } catch (NumberFormatException e) { - } - } - } - - // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be - // ignored. - if (networkTypeBitmask == 0) { - networkTypeBitmask = - ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); - } - return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2], - portFromString(a[3]), UriFromString(a[7]), a[8], - portFromString(a[9]), a[4], a[5], authType, - getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)), - getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol), - carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime, - maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId, - carrierId, skip464xlat); - } - - /** - * Creates an array of ApnSetting objects from a string. - * - * @param data the string to read. - * - * Builds on top of the same format used by fromString, but allows for multiple entries - * separated by ";". - * - * @hide - */ - public static List<ApnSetting> arrayFromString(String data) { - List<ApnSetting> retVal = new ArrayList<ApnSetting>(); - if (TextUtils.isEmpty(data)) { - return retVal; - } - String[] apnStrings = data.split("\\s*;\\s*"); - for (String apnString : apnStrings) { - ApnSetting apn = fromString(apnString); - if (apn != null) { - retVal.add(apn); - } - } - return retVal; + return new Builder() + .setId(apn.mId) + .setOperatorNumeric(apn.mOperatorNumeric) + .setEntryName(apn.mEntryName) + .setApnName(apn.mApnName) + .setProxyAddress(apn.mProxyAddress) + .setProxyPort(apn.mProxyPort) + .setMmsc(apn.mMmsc) + .setMmsProxyAddress(apn.mMmsProxyAddress) + .setMmsProxyPort(apn.mMmsProxyPort) + .setUser(apn.mUser) + .setPassword(apn.mPassword) + .setAuthType(apn.mAuthType) + .setApnTypeBitmask(apn.mApnTypeBitmask) + .setProtocol(apn.mProtocol) + .setRoamingProtocol(apn.mRoamingProtocol) + .setCarrierEnabled(apn.mCarrierEnabled) + .setNetworkTypeBitmask(apn.mNetworkTypeBitmask) + .setProfileId(apn.mProfileId) + .setModemCognitive(apn.mPersistent) + .setMaxConns(apn.mMaxConns) + .setWaitTime(apn.mWaitTime) + .setMaxConnsTime(apn.mMaxConnsTime) + .setMtuV4(apn.mMtuV4) + .setMtuV6(apn.mMtuV6) + .setMvnoType(apn.mMvnoType) + .setMvnoMatchData(apn.mMvnoMatchData) + .setApnSetId(apn.mApnSetId) + .setCarrierId(apn.mCarrierId) + .setSkip464Xlat(apn.mSkip464Xlat) + .buildWithoutCheck(); } /** @@ -1251,7 +1042,7 @@ public class ApnSetting implements Parcelable { */ public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("[ApnSettingV7] ") + sb.append("[ApnSetting] ") .append(mEntryName) .append(", ").append(mId) .append(", ").append(mOperatorNumeric) @@ -1272,7 +1063,8 @@ public class ApnSetting implements Parcelable { sb.append(", ").append(mMaxConns); sb.append(", ").append(mWaitTime); sb.append(", ").append(mMaxConnsTime); - sb.append(", ").append(mMtu); + sb.append(", ").append(mMtuV4); + sb.append(", ").append(mMtuV6); sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType)); sb.append(", ").append(mMvnoMatchData); sb.append(", ").append(mPermanentFailed); @@ -1343,9 +1135,9 @@ public class ApnSetting implements Parcelable { public int hashCode() { return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress, mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric, - mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId, - mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData, - mApnSetId, mCarrierId, mSkip464Xlat); + mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask, + mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, + mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat); } @Override @@ -1357,33 +1149,34 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mId, other.mId) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && Objects.equals(mProtocol, other.mProtocol) - && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mId, other.mId) + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && Objects.equals(mProtocol, other.mProtocol) + && Objects.equals(mRoamingProtocol, other.mRoamingProtocol) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1406,31 +1199,32 @@ public class ApnSetting implements Parcelable { ApnSetting other = (ApnSetting) o; return mEntryName.equals(other.mEntryName) - && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) - && Objects.equals(mApnName, other.mApnName) - && Objects.equals(mProxyAddress, other.mProxyAddress) - && Objects.equals(mMmsc, other.mMmsc) - && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) - && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) - && Objects.equals(mProxyPort, other.mProxyPort) - && Objects.equals(mUser, other.mUser) - && Objects.equals(mPassword, other.mPassword) - && Objects.equals(mAuthType, other.mAuthType) - && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) - && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) - && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) - && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) - && Objects.equals(mProfileId, other.mProfileId) - && Objects.equals(mPersistent, other.mPersistent) - && Objects.equals(mMaxConns, other.mMaxConns) - && Objects.equals(mWaitTime, other.mWaitTime) - && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) - && Objects.equals(mMtu, other.mMtu) - && Objects.equals(mMvnoType, other.mMvnoType) - && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) - && Objects.equals(mApnSetId, other.mApnSetId) - && Objects.equals(mCarrierId, other.mCarrierId) - && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); + && Objects.equals(mOperatorNumeric, other.mOperatorNumeric) + && Objects.equals(mApnName, other.mApnName) + && Objects.equals(mProxyAddress, other.mProxyAddress) + && Objects.equals(mMmsc, other.mMmsc) + && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress) + && Objects.equals(mMmsProxyPort, other.mMmsProxyPort) + && Objects.equals(mProxyPort, other.mProxyPort) + && Objects.equals(mUser, other.mUser) + && Objects.equals(mPassword, other.mPassword) + && Objects.equals(mAuthType, other.mAuthType) + && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask) + && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol)) + && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol)) + && Objects.equals(mCarrierEnabled, other.mCarrierEnabled) + && Objects.equals(mProfileId, other.mProfileId) + && Objects.equals(mPersistent, other.mPersistent) + && Objects.equals(mMaxConns, other.mMaxConns) + && Objects.equals(mWaitTime, other.mWaitTime) + && Objects.equals(mMaxConnsTime, other.mMaxConnsTime) + && Objects.equals(mMtuV4, other.mMtuV4) + && Objects.equals(mMtuV6, other.mMtuV6) + && Objects.equals(mMvnoType, other.mMvnoType) + && Objects.equals(mMvnoMatchData, other.mMvnoMatchData) + && Objects.equals(mApnSetId, other.mApnSetId) + && Objects.equals(mCarrierId, other.mCarrierId) + && Objects.equals(mSkip464Xlat, other.mSkip464Xlat); } /** @@ -1732,7 +1526,7 @@ public class ApnSetting implements Parcelable { dest.writeString(mApnName); dest.writeString(mProxyAddress); dest.writeInt(mProxyPort); - dest.writeValue(mMmsc); + dest.writeParcelable(mMmsc, flags); dest.writeString(mMmsProxyAddress); dest.writeInt(mMmsProxyPort); dest.writeString(mUser); @@ -1742,40 +1536,53 @@ public class ApnSetting implements Parcelable { dest.writeInt(mProtocol); dest.writeInt(mRoamingProtocol); dest.writeBoolean(mCarrierEnabled); - dest.writeInt(mMvnoType); dest.writeInt(mNetworkTypeBitmask); + dest.writeInt(mProfileId); + dest.writeBoolean(mPersistent); + dest.writeInt(mMaxConns); + dest.writeInt(mWaitTime); + dest.writeInt(mMaxConnsTime); + dest.writeInt(mMtuV4); + dest.writeInt(mMtuV6); + dest.writeInt(mMvnoType); + dest.writeString(mMvnoMatchData); dest.writeInt(mApnSetId); dest.writeInt(mCarrierId); dest.writeInt(mSkip464Xlat); } private static ApnSetting readFromParcel(Parcel in) { - final int id = in.readInt(); - final String operatorNumeric = in.readString(); - final String entryName = in.readString(); - final String apnName = in.readString(); - final String proxy = in.readString(); - final int port = in.readInt(); - final Uri mmsc = (Uri) in.readValue(Uri.class.getClassLoader()); - final String mmsProxy = in.readString(); - final int mmsPort = in.readInt(); - final String user = in.readString(); - final String password = in.readString(); - final int authType = in.readInt(); - final int apnTypesBitmask = in.readInt(); - final int protocol = in.readInt(); - final int roamingProtocol = in.readInt(); - final boolean carrierEnabled = in.readBoolean(); - final int mvnoType = in.readInt(); - final int networkTypeBitmask = in.readInt(); - final int apnSetId = in.readInt(); - final int carrierId = in.readInt(); - final int skip464xlat = in.readInt(); - - return makeApnSetting(id, operatorNumeric, entryName, apnName, - proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask, - protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false, - 0, 0, 0, 0, mvnoType, null, apnSetId, carrierId, skip464xlat); + return new Builder() + .setId(in.readInt()) + .setOperatorNumeric(in.readString()) + .setEntryName(in.readString()) + .setApnName(in.readString()) + .setProxyAddress(in.readString()) + .setProxyPort(in.readInt()) + .setMmsc(in.readParcelable(Uri.class.getClassLoader())) + .setMmsProxyAddress(in.readString()) + .setMmsProxyPort(in.readInt()) + .setUser(in.readString()) + .setPassword(in.readString()) + .setAuthType(in.readInt()) + .setApnTypeBitmask(in.readInt()) + .setProtocol(in.readInt()) + .setRoamingProtocol(in.readInt()) + .setCarrierEnabled(in.readBoolean()) + .setNetworkTypeBitmask(in.readInt()) + .setProfileId(in.readInt()) + .setModemCognitive(in.readBoolean()) + .setMaxConns(in.readInt()) + .setWaitTime(in.readInt()) + .setMaxConnsTime(in.readInt()) + .setMtuV4(in.readInt()) + .setMtuV6(in.readInt()) + .setMvnoType(in.readInt()) + .setMvnoMatchData(in.readString()) + .setApnSetId(in.readInt()) + .setCarrierId(in.readInt()) + .setSkip464Xlat(in.readInt()) + .buildWithoutCheck(); } public static final @android.annotation.NonNull Parcelable.Creator<ApnSetting> CREATOR = @@ -1834,13 +1641,14 @@ public class ApnSetting implements Parcelable { private int mMmsProxyPort = UNSPECIFIED_INT; private String mUser; private String mPassword; - private int mAuthType; + private int mAuthType = AUTH_TYPE_UNKNOWN; private int mApnTypeBitmask; private int mId; private String mOperatorNumeric; private int mProtocol = UNSPECIFIED_INT; private int mRoamingProtocol = UNSPECIFIED_INT; - private int mMtu; + private int mMtuV4; + private int mMtuV6; private int mNetworkTypeBitmask; private boolean mCarrierEnabled; private int mProfileId; @@ -1863,20 +1671,34 @@ public class ApnSetting implements Parcelable { * Sets the unique database id for this entry. * * @param id the unique database id to set for this entry + * @hide */ - private Builder setId(int id) { + public Builder setId(int id) { this.mId = id; return this; } /** - * Set the MTU size of the mobile interface to which the APN connected. + * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. + * + * @param mtuV4 the MTU size to set for the APN + * @hide + */ + public Builder setMtuV4(int mtuV4) { + this.mMtuV4 = mtuV4; + return this; + } + + /** + * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value + * is used only if MTU size is not provided in {@link DataCallResponse}. * - * @param mtu the MTU size to set for the APN + * @param mtuV6 the MTU size to set for the APN * @hide */ - public Builder setMtu(int mtu) { - this.mMtu = mtu; + public Builder setMtuV6(int mtuV6) { + this.mMtuV6 = mtuV6; return this; } @@ -2237,7 +2059,8 @@ public class ApnSetting implements Parcelable { | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { - return null; + throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName=" + + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask); } return new ApnSetting(this); } diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java index f2a124901bc4..93903d2658cd 100644 --- a/telephony/java/android/telephony/data/DataProfile.java +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -25,13 +25,11 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.ApnType; +import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.NetworkTypeBitMask; import android.telephony.data.ApnSetting.AuthType; import android.text.TextUtils; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.util.TelephonyUtils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -62,152 +60,141 @@ public final class DataProfile implements Parcelable { /** 3GPP2 type data profile */ public static final int TYPE_3GPP2 = 2; - private final int mProfileId; - - private final String mApn; - - @ProtocolType - private final int mProtocolType; - - @AuthType - private final int mAuthType; - - private final String mUserName; - - private final String mPassword; - - @Type - private final int mType; - - private final int mMaxConnectionsTime; - - private final int mMaxConnections; - - private final int mWaitTime; - - private final boolean mEnabled; - - @ApnType - private final int mSupportedApnTypesBitmask; - - @ProtocolType - private final int mRoamingProtocolType; - - @NetworkTypeBitMask - private final int mBearerBitmask; + private final @Type int mType; - private final int mMtuV4; + private final @Nullable ApnSetting mApnSetting; - private final int mMtuV6; - - private final boolean mPersistent; + private final @Nullable TrafficDescriptor mTrafficDescriptor; private final boolean mPreferred; - /** @hide */ - private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType, - String userName, String password, int type, int maxConnectionsTime, - int maxConnections, int waitTime, boolean enabled, - @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType, - @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent, - boolean preferred) { - this.mProfileId = profileId; - this.mApn = apn; - this.mProtocolType = protocolType; - if (authType == -1) { - authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE - : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; - } - this.mAuthType = authType; - this.mUserName = userName; - this.mPassword = password; - this.mType = type; - this.mMaxConnectionsTime = maxConnectionsTime; - this.mMaxConnections = maxConnections; - this.mWaitTime = waitTime; - this.mEnabled = enabled; - this.mSupportedApnTypesBitmask = supportedApnTypesBitmask; - this.mRoamingProtocolType = roamingProtocolType; - this.mBearerBitmask = bearerBitmask; - this.mMtuV4 = mtuV4; - this.mMtuV6 = mtuV6; - this.mPersistent = persistent; - this.mPreferred = preferred; + private DataProfile(@NonNull Builder builder) { + mApnSetting = builder.mApnSetting; + mTrafficDescriptor = builder.mTrafficDescriptor; + mPreferred = builder.mPreferred; + + if (builder.mType != -1) { + mType = builder.mType; + } else if (mApnSetting != null) { + int networkTypes = mApnSetting.getNetworkTypeBitmask(); + + if (networkTypes == 0) { + mType = DataProfile.TYPE_COMMON; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2) + == networkTypes) { + mType = DataProfile.TYPE_3GPP2; + } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP) + == networkTypes) { + mType = DataProfile.TYPE_3GPP; + } else { + mType = DataProfile.TYPE_COMMON; + } + } else { + mType = DataProfile.TYPE_COMMON; + } } private DataProfile(Parcel source) { - mProfileId = source.readInt(); - mApn = source.readString(); - mProtocolType = source.readInt(); - mAuthType = source.readInt(); - mUserName = source.readString(); - mPassword = source.readString(); mType = source.readInt(); - mMaxConnectionsTime = source.readInt(); - mMaxConnections = source.readInt(); - mWaitTime = source.readInt(); - mEnabled = source.readBoolean(); - mSupportedApnTypesBitmask = source.readInt(); - mRoamingProtocolType = source.readInt(); - mBearerBitmask = source.readInt(); - mMtuV4 = source.readInt(); - mMtuV6 = source.readInt(); - mPersistent = source.readBoolean(); + mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader()); + mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader()); mPreferred = source.readBoolean(); } /** * @return Id of the data profile. */ - public int getProfileId() { return mProfileId; } + public int getProfileId() { + if (mApnSetting != null) { + return mApnSetting.getProfileId(); + } + return 0; + } /** * @return The APN (Access Point Name) to establish data connection. This is a string * specifically defined by the carrier. */ @NonNull - public String getApn() { return mApn; } + public String getApn() { + if (mApnSetting != null) { + return TextUtils.emptyIfNull(mApnSetting.getApnName()); + } + return ""; + } /** * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getProtocolType() { return mProtocolType; } + public @ProtocolType int getProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The authentication protocol used for this PDP context. */ - public @AuthType int getAuthType() { return mAuthType; } + public @AuthType int getAuthType() { + if (mApnSetting != null) { + return mApnSetting.getAuthType(); + } + return ApnSetting.AUTH_TYPE_NONE; + } /** * @return The username for APN. Can be null. */ @Nullable - public String getUserName() { return mUserName; } + public String getUserName() { + if (mApnSetting != null) { + return mApnSetting.getUser(); + } + return null; + } /** * @return The password for APN. Can be null. */ @Nullable - public String getPassword() { return mPassword; } + public String getPassword() { + if (mApnSetting != null) { + return mApnSetting.getPassword(); + } + return null; + } /** * @return The profile type. */ - public @Type int getType() { return mType; } + public @Type int getType() { + return mType; + } /** * @return The period in seconds to limit the maximum connections. * * @hide */ - public int getMaxConnectionsTime() { return mMaxConnectionsTime; } + public int getMaxConnectionsTime() { + if (mApnSetting != null) { + return mApnSetting.getMaxConnsTime(); + } + return 0; + } /** * @return The maximum connections allowed. * * @hide */ - public int getMaxConnections() { return mMaxConnections; } + public int getMaxConnections() { + if (mApnSetting != null) { + return mApnSetting.getMaxConns(); + } + return 0; + } /** * @return The required wait time in seconds after a successful UE initiated disconnect of a @@ -216,57 +203,117 @@ public final class DataProfile implements Parcelable { * * @hide */ - public int getWaitTime() { return mWaitTime; } + public int getWaitTime() { + if (mApnSetting != null) { + return mApnSetting.getWaitTime(); + } + return 0; + } /** * @return True if the profile is enabled. */ - public boolean isEnabled() { return mEnabled; } + public boolean isEnabled() { + if (mApnSetting != null) { + return mApnSetting.isEnabled(); + } + return false; + } /** * @return The supported APN types bitmask. */ - public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; } + public @ApnType int getSupportedApnTypesBitmask() { + if (mApnSetting != null) { + return mApnSetting.getApnTypeBitmask(); + } + return ApnSetting.TYPE_NONE; + } /** * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1. */ - public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; } + public @ProtocolType int getRoamingProtocolType() { + if (mApnSetting != null) { + return mApnSetting.getRoamingProtocol(); + } + return ApnSetting.PROTOCOL_IP; + } /** * @return The bearer bitmask indicating the applicable networks for this data profile. */ - public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; } + public @NetworkTypeBitMask int getBearerBitmask() { + if (mApnSetting != null) { + return mApnSetting.getNetworkTypeBitmask(); + } + return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN; + } /** * @return The maximum transmission unit (MTU) size in bytes. * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead. */ @Deprecated - public int getMtu() { return mMtuV4; } + public int getMtu() { + return getMtuV4(); + } /** * This replaces the deprecated method getMtu. * @return The maximum transmission unit (MTU) size in bytes, for IPv4. */ - public int getMtuV4() { return mMtuV4; } + public int getMtuV4() { + if (mApnSetting != null) { + return mApnSetting.getMtuV4(); + } + return 0; + } /** * @return The maximum transmission unit (MTU) size in bytes, for IPv6. */ - public int getMtuV6() { return mMtuV6; } + public int getMtuV6() { + if (mApnSetting != null) { + return mApnSetting.getMtuV6(); + } + return 0; + } /** * @return {@code true} if modem must persist this data profile. */ - public boolean isPersistent() { return mPersistent; } + public boolean isPersistent() { + if (mApnSetting != null) { + return mApnSetting.isPersistent(); + } + return false; + } /** * @return {@code true} if this data profile was used to bring up the last default * (i.e internet) data connection successfully, or the one chosen by the user in Settings' * APN editor. For one carrier there can be only one profiled preferred. */ - public boolean isPreferred() { return mPreferred; } + public boolean isPreferred() { + return mPreferred; + } + + /** + * @return The APN setting + * @hide TODO: Remove before T is released. + */ + public @Nullable ApnSetting getApnSetting() { + return mApnSetting; + } + + /** + * @return The traffic descriptor + * @hide TODO: Remove before T is released. + */ + public @Nullable TrafficDescriptor getTrafficDescriptor() { + return mTrafficDescriptor; + } @Override public int describeContents() { @@ -276,34 +323,15 @@ public final class DataProfile implements Parcelable { @NonNull @Override public String toString() { - return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType - + "/" + (TelephonyUtils.IS_USER ? "***/***/***" : - (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/" - + mMaxConnectionsTime + "/" + mMaxConnections + "/" - + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/" - + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/" - + mPersistent + "/" + mPreferred; + return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred=" + + mPreferred; } @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mProfileId); - dest.writeString(mApn); - dest.writeInt(mProtocolType); - dest.writeInt(mAuthType); - dest.writeString(mUserName); - dest.writeString(mPassword); dest.writeInt(mType); - dest.writeInt(mMaxConnectionsTime); - dest.writeInt(mMaxConnections); - dest.writeInt(mWaitTime); - dest.writeBoolean(mEnabled); - dest.writeInt(mSupportedApnTypesBitmask); - dest.writeInt(mRoamingProtocolType); - dest.writeInt(mBearerBitmask); - dest.writeInt(mMtuV4); - dest.writeInt(mMtuV6); - dest.writeBoolean(mPersistent); + dest.writeParcelable(mApnSetting, flags); + dest.writeParcelable(mTrafficDescriptor, flags); dest.writeBoolean(mPreferred); } @@ -321,36 +349,18 @@ public final class DataProfile implements Parcelable { }; @Override - public boolean equals(@Nullable Object o) { + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DataProfile that = (DataProfile) o; - return mProfileId == that.mProfileId - && mProtocolType == that.mProtocolType - && mAuthType == that.mAuthType - && mType == that.mType - && mMaxConnectionsTime == that.mMaxConnectionsTime - && mMaxConnections == that.mMaxConnections - && mWaitTime == that.mWaitTime - && mEnabled == that.mEnabled - && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask - && mRoamingProtocolType == that.mRoamingProtocolType - && mBearerBitmask == that.mBearerBitmask - && mMtuV4 == that.mMtuV4 - && mMtuV6 == that.mMtuV6 - && mPersistent == that.mPersistent - && mPreferred == that.mPreferred - && Objects.equals(mApn, that.mApn) - && Objects.equals(mUserName, that.mUserName) - && Objects.equals(mPassword, that.mPassword); + return mType == that.mType + && Objects.equals(mApnSetting, that.mApnSetting) + && Objects.equals(mTrafficDescriptor, that.mTrafficDescriptor); } @Override public int hashCode() { - return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType, - mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + return Objects.hash(mType, mApnSetting, mTrafficDescriptor); } /** @@ -383,13 +393,7 @@ public final class DataProfile implements Parcelable { private String mPassword; @Type - private int mType; - - private int mMaxConnectionsTime; - - private int mMaxConnections; - - private int mWaitTime; + private int mType = -1; private boolean mEnabled; @@ -410,6 +414,10 @@ public final class DataProfile implements Parcelable { private boolean mPreferred; + private ApnSetting mApnSetting; + + private TrafficDescriptor mTrafficDescriptor; + /** * Default constructor for Builder. */ @@ -496,48 +504,6 @@ public final class DataProfile implements Parcelable { } /** - * Set the period in seconds to limit the maximum connections. - * - * @param maxConnectionsTime The profile type - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) { - mMaxConnectionsTime = maxConnectionsTime; - return this; - } - - /** - * Set the maximum connections allowed. - * - * @param maxConnections The maximum connections allowed. - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setMaxConnections(int maxConnections) { - mMaxConnections = maxConnections; - return this; - } - - /** - * Set the period in seconds to limit the maximum connections. - * - * @param waitTime The required wait time in seconds after a successful UE initiated - * disconnect of a given PDN connection before the device can send a new PDN connection - * request for that given PDN. - * - * @return The same instance of the builder. - * - * @hide - */ - public @NonNull Builder setWaitTime(int waitTime) { - mWaitTime = waitTime; - return this; - } - - /** * Enable the data profile * * @param isEnabled {@code true} to enable the data profile, otherwise disable. @@ -587,8 +553,9 @@ public final class DataProfile implements Parcelable { * * @param mtu The maximum transmission unit (MTU) size in bytes. * @return The same instance of the builder. - * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead. + * @deprecated use {@link #setApnSetting(ApnSetting)} instead. */ + @Deprecated public @NonNull Builder setMtu(int mtu) { mMtuV4 = mMtuV6 = mtu; return this; @@ -631,7 +598,7 @@ public final class DataProfile implements Parcelable { } /** - * Set data profile as persistent/non-persistent + * Set data profile as persistent/non-persistent. * * @param isPersistent {@code true} if this data profile was used to bring up the last * default (i.e internet) data connection successfully. @@ -643,15 +610,63 @@ public final class DataProfile implements Parcelable { } /** + * Set APN setting. + * + * @param apnSetting APN setting + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) { + mApnSetting = apnSetting; + return this; + } + + /** + * Set traffic descriptor. + * + * @param trafficDescriptor Traffic descriptor + * @return The same instance of the builder + * + * @hide // TODO: Remove before T is released. + */ + public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) { + mTrafficDescriptor = trafficDescriptor; + return this; + } + + /** * Build the DataProfile object * * @return The data profile object */ public @NonNull DataProfile build() { - return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, - mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled, - mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6, - mPersistent, mPreferred); + if (mApnSetting == null && mApn != null) { + // This is for backwards compatibility. + mApnSetting = new ApnSetting.Builder() + .setEntryName(mApn) + .setApnName(mApn) + .setApnTypeBitmask(mSupportedApnTypesBitmask) + .setAuthType(mAuthType) + .setCarrierEnabled(mEnabled) + .setModemCognitive(mPersistent) + .setMtuV4(mMtuV4) + .setMtuV6(mMtuV6) + .setNetworkTypeBitmask(mBearerBitmask) + .setProfileId(mProfileId) + .setPassword(mPassword) + .setProtocol(mProtocolType) + .setRoamingProtocol(mRoamingProtocolType) + .setUser(mUserName) + .build(); + } + + if (mApnSetting == null && mTrafficDescriptor == null) { + throw new IllegalArgumentException("APN setting and traffic descriptor can't be " + + "both null."); + } + + return new DataProfile(this); } } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 232a5d881722..d586a4a38f73 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2224,6 +2224,20 @@ interface ITelephony { List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId); /** + * Enable or disable Voice over NR (VoNR) + * @param subId the subscription ID that this action applies to. + * @param enabled enable or disable VoNR. + * @return operation result. + */ + int setVoNrEnabled(int subId, boolean enabled); + + /** + * Is voice over NR enabled + * @return true if VoNR is enabled else false + */ + boolean isVoNrEnabled(int subId); + + /** * Enable/Disable E-UTRA-NR Dual Connectivity * @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for * details diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index b73f8271da1f..866fd2c7394e 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -528,6 +528,8 @@ public interface RILConstants { int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222; int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223; int RIL_REQUEST_GET_SLICING_CONFIG = 224; + int RIL_REQUEST_ENABLE_VONR = 225; + int RIL_REQUEST_IS_VONR_ENABLED = 226; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS index b5561010e7f9..c1221e3940d2 100644 --- a/tests/FlickerTests/OWNERS +++ b/tests/FlickerTests/OWNERS @@ -1,3 +1,4 @@ # Bug component: 909476 include /services/core/java/com/android/server/wm/OWNERS -natanieljr@google.com
\ No newline at end of file +natanieljr@google.com +pablogamito@google.com diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 5253c3e9b77c..2b0037eaf8eb 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -16,6 +16,7 @@ package com.android.server.vcn; +import static android.net.IpSecManager.IpSecTunnelInterface; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; @@ -24,6 +25,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; @@ -36,8 +39,11 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.net.IpSecManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -59,6 +65,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.InetAddress; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -71,6 +79,8 @@ import java.util.UUID; public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid() + 1; + private static final String LOOPBACK_IFACE = "lo"; + private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID()); private static final int TEST_SIM_SLOT_INDEX = 1; private static final int TEST_SUBSCRIPTION_ID_1 = 2; @@ -78,6 +88,12 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_SUBSCRIPTION_ID_2 = 3; private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class); private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP; + private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6"; + private static final int TEST_MTU = 1300; + private static final int TEST_MTU_DELTA = 64; + private static final List<LinkAddress> TEST_INTERNAL_ADDRESSES = + Arrays.asList(new LinkAddress(DUMMY_ADDR, 16)); + private static final List<InetAddress> TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR); private static final int TEST_UPSTREAM_BANDWIDTH = 1234; private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345; @@ -169,6 +185,59 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { } @Test + public void testBuildLinkProperties() throws Exception { + final IpSecTunnelInterface tunnelIface = + mContext.getSystemService(IpSecManager.class) + .createIpSecTunnelInterface( + DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network); + + final LinkProperties underlyingLp = new LinkProperties(); + underlyingLp.setInterfaceName(LOOPBACK_IFACE); + underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES); + doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final VcnChildSessionConfiguration childSessionConfig = + mock(VcnChildSessionConfiguration.class); + doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses(); + doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers(); + + UnderlyingNetworkRecord record = + new UnderlyingNetworkRecord( + mock(Network.class, CALLS_REAL_METHODS), + new NetworkCapabilities.Builder().build(), + underlyingLp, + false); + + final LinkProperties vcnLp1 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + // Instead of having to recalculate the final MTU (after accounting for IPsec overhead), + // calculate another set of Link Properties with a lower MTU, and calculate the delta. + doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + final LinkProperties vcnLp2 = + mGatewayConnection.buildConnectedLinkProperties( + VcnGatewayConnectionConfigTest.buildTestConfig(), + tunnelIface, + childSessionConfig, + record); + + verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE); + + assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName()); + assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses()); + assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers()); + assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes()); + assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu()); + } + + @Test public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() { verifyWakeLockSetUp(); diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS index 69dfcc98340d..4f655e54a7c2 100644 --- a/tools/aapt2/OWNERS +++ b/tools/aapt2/OWNERS @@ -1,4 +1,4 @@ set noparent toddke@google.com -rtmitchell@google.com +zyy@google.com patb@google.com
\ No newline at end of file |