Merge "Add FREE ShortCodes for EG and NG for Constellation Project"
diff --git a/Android.bp b/Android.bp
index d976b91..00b4198 100644
--- a/Android.bp
+++ b/Android.bp
@@ -294,6 +294,7 @@
srcs: [
":framework-non-updatable-sources",
"core/java/**/*.logtags",
+ ":apex-info-list",
],
aidl: {
generate_get_transaction_name: true,
diff --git a/PACKAGE_MANAGER_OWNERS b/PACKAGE_MANAGER_OWNERS
new file mode 100644
index 0000000..e4549b4
--- /dev/null
+++ b/PACKAGE_MANAGER_OWNERS
@@ -0,0 +1,3 @@
+chiuwinson@google.com
+patb@google.com
+schfan@google.com
\ No newline at end of file
diff --git a/core/api/current.txt b/core/api/current.txt
index 0eba9d7..b54a747 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -112,6 +112,7 @@
field public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
+ field public static final String NEARBY_WIFI_DEVICES = "android.permission.NEARBY_WIFI_DEVICES";
field public static final String NFC = "android.permission.NFC";
field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO";
field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 172818d..49df45a 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -312,7 +312,7 @@
package android.provider {
public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static java.util.Map<java.lang.String,java.util.List<android.content.ContentValues>> queryRawContactEntity(@NonNull android.content.Context, long);
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static java.util.Map<java.lang.String,java.util.List<android.content.ContentValues>> queryRawContactEntity(@NonNull android.content.ContentResolver, long);
}
public final class DeviceConfig {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 13f7cfb..db3cedd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1935,6 +1935,22 @@
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
}
+ public final class BluetoothActivityEnergyInfo implements android.os.Parcelable {
+ method public int getBluetoothStackState();
+ method public long getControllerEnergyUsed();
+ method public long getControllerIdleTimeMillis();
+ method public long getControllerRxTimeMillis();
+ method public long getControllerTxTimeMillis();
+ method public long getTimestampMillis();
+ method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic();
+ method public boolean isValid();
+ field public static final int BT_STACK_STATE_INVALID = 0; // 0x0
+ field public static final int BT_STACK_STATE_STATE_ACTIVE = 1; // 0x1
+ field public static final int BT_STACK_STATE_STATE_IDLE = 3; // 0x3
+ field public static final int BT_STACK_STATE_STATE_SCANNING = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothActivityEnergyInfo> CREATOR;
+ }
+
public final class BluetoothAdapter {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean);
@@ -2234,6 +2250,13 @@
method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]);
}
+ public final class UidTraffic implements java.lang.Cloneable android.os.Parcelable {
+ method public long getRxBytes();
+ method public long getTxBytes();
+ method public int getUid();
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.UidTraffic> CREATOR;
+ }
+
}
package android.bluetooth.le {
@@ -9139,6 +9162,7 @@
field public static final String NAMESPACE_MEDIA = "media";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
field public static final String NAMESPACE_OTA = "ota";
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5f2c456..e08a493 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -158,10 +158,7 @@
"android/util/LocalLog.java",
// This should be android.util.IndentingPrintWriter, but it's not available in all branches.
"com/android/internal/util/IndentingPrintWriter.java",
- "com/android/internal/util/IState.java",
"com/android/internal/util/MessageUtils.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
"com/android/internal/util/WakeupMessage.java",
],
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d932a29..0b336f6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1292,6 +1292,9 @@
/** @hide */
public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING;
+ /** @hide */
+ public static final int OP_NEARBY_WIFI_DEVICES = AppProtoEnums.APP_OP_NEARBY_WIFI_DEVICES;
+
/**
* Activity recognition being accessed by an activity recognition source, which
* is a component that already has access since it is the one that detects
@@ -1312,7 +1315,7 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 116;
+ public static final int _NUM_OP = 117;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1731,6 +1734,8 @@
public static final String OPSTR_MANAGE_MEDIA = "android:manage_media";
/** @hide */
public static final String OPSTR_UWB_RANGING = "android:uwb_ranging";
+ /** @hide */
+ public static final String OPSTR_NEARBY_WIFI_DEVICES = "android:nearby_wifi_devices";
/**
* Activity recognition being accessed by an activity recognition source, which
@@ -1819,6 +1824,7 @@
OP_BLUETOOTH_CONNECT,
OP_BLUETOOTH_ADVERTISE,
OP_UWB_RANGING,
+ OP_NEARBY_WIFI_DEVICES,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
@@ -1963,6 +1969,7 @@
OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION_SOURCE
OP_BLUETOOTH_ADVERTISE, // OP_BLUETOOTH_ADVERTISE
OP_RECORD_INCOMING_PHONE_AUDIO, // OP_RECORD_INCOMING_PHONE_AUDIO
+ OP_NEARBY_WIFI_DEVICES, // OP_NEARBY_WIFI_DEVICES
};
/**
@@ -2085,6 +2092,7 @@
OPSTR_ACTIVITY_RECOGNITION_SOURCE,
OPSTR_BLUETOOTH_ADVERTISE,
OPSTR_RECORD_INCOMING_PHONE_AUDIO,
+ OPSTR_NEARBY_WIFI_DEVICES,
};
/**
@@ -2208,6 +2216,7 @@
"ACTIVITY_RECOGNITION_SOURCE",
"BLUETOOTH_ADVERTISE",
"RECORD_INCOMING_PHONE_AUDIO",
+ "NEARBY_WIFI_DEVICES"
};
/**
@@ -2332,6 +2341,7 @@
null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE,
Manifest.permission.BLUETOOTH_ADVERTISE,
null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO,
+ Manifest.permission.NEARBY_WIFI_DEVICES,
};
/**
@@ -2456,6 +2466,7 @@
null, // ACTIVITY_RECOGNITION_SOURCE
null, // BLUETOOTH_ADVERTISE
null, // RECORD_INCOMING_PHONE_AUDIO
+ null, // NEARBY_WIFI_DEVICES
};
/**
@@ -2579,6 +2590,7 @@
null, // ACTIVITY_RECOGNITION_SOURCE
null, // BLUETOOTH_ADVERTISE
null, // RECORD_INCOMING_PHONE_AUDIO
+ null, // NEARBY_WIFI_DEVICES
};
/**
@@ -2701,6 +2713,7 @@
AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE
AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE
AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO
+ AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES
};
/**
@@ -2827,6 +2840,7 @@
false, // ACTIVITY_RECOGNITION_SOURCE
false, // BLUETOOTH_ADVERTISE
false, // RECORD_INCOMING_PHONE_AUDIO
+ false, // NEARBY_WIFI_DEVICES
};
/**
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index e0e9b62..4da51c1 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -28,6 +28,7 @@
per-file Service* = file:/services/core/java/com/android/server/am/OWNERS
per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
+per-file UiAutomation.java = file:/services/accessibility/OWNERS
# ActivityThread
per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 32ea41b..e2fd359 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1914,39 +1914,6 @@
public abstract T createService() throws ServiceNotFoundException;
}
- /**
- * Like StaticServiceFetcher, creates only one instance of the service per application, but when
- * creating the service for the first time, passes it the application context of the creating
- * application.
- *
- * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
- * case where multiple application components each have their own ConnectivityManager object.
- */
- static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
- private T mCachedInstance;
-
- @Override
- public final T getService(ContextImpl ctx) {
- synchronized (StaticApplicationContextServiceFetcher.this) {
- if (mCachedInstance == null) {
- Context appContext = ctx.getApplicationContext();
- // If the application context is null, we're either in the system process or
- // it's the application context very early in app initialization. In both these
- // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
- // to the service. http://b/27532714 .
- try {
- mCachedInstance = createService(appContext != null ? appContext : ctx);
- } catch (ServiceNotFoundException e) {
- onServiceNotFound(e);
- }
- }
- return mCachedInstance;
- }
- }
-
- public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
- }
-
/** @hide */
public static void onServiceNotFound(ServiceNotFoundException e) {
// We're mostly interested in tracking down long-lived core system
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
index df065bf..c17a7b4 100644
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
@@ -16,18 +16,26 @@
package android.bluetooth;
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
/**
* Record of energy and activity information from controller and
* underlying bt stack state.Timestamp the record with system
- * time
+ * time.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
public final class BluetoothActivityEnergyInfo implements Parcelable {
private final long mTimestamp;
private int mBluetoothStackState;
@@ -35,13 +43,24 @@
private long mControllerRxTimeMs;
private long mControllerIdleTimeMs;
private long mControllerEnergyUsed;
- private UidTraffic[] mUidTraffic;
+ private List<UidTraffic> mUidTraffic;
+
+ /** @hide */
+ @IntDef(prefix = { "BT_STACK_STATE_" }, value = {
+ BT_STACK_STATE_INVALID,
+ BT_STACK_STATE_STATE_ACTIVE,
+ BT_STACK_STATE_STATE_SCANNING,
+ BT_STACK_STATE_STATE_IDLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BluetoothStackState {}
public static final int BT_STACK_STATE_INVALID = 0;
public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
public static final int BT_STACK_STATE_STATE_SCANNING = 2;
public static final int BT_STACK_STATE_STATE_IDLE = 3;
+ /** @hide */
public BluetoothActivityEnergyInfo(long timestamp, int stackState,
long txTime, long rxTime, long idleTime, long energyUsed) {
mTimestamp = timestamp;
@@ -52,17 +71,18 @@
mControllerEnergyUsed = energyUsed;
}
- @SuppressWarnings("unchecked")
- BluetoothActivityEnergyInfo(Parcel in) {
+ /** @hide */
+ private BluetoothActivityEnergyInfo(Parcel in) {
mTimestamp = in.readLong();
mBluetoothStackState = in.readInt();
mControllerTxTimeMs = in.readLong();
mControllerRxTimeMs = in.readLong();
mControllerIdleTimeMs = in.readLong();
mControllerEnergyUsed = in.readLong();
- mUidTraffic = in.createTypedArray(UidTraffic.CREATOR);
+ mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR);
}
+ /** @hide */
@Override
public String toString() {
return "BluetoothActivityEnergyInfo{"
@@ -72,11 +92,11 @@
+ " mControllerRxTimeMs=" + mControllerRxTimeMs
+ " mControllerIdleTimeMs=" + mControllerIdleTimeMs
+ " mControllerEnergyUsed=" + mControllerEnergyUsed
- + " mUidTraffic=" + Arrays.toString(mUidTraffic)
+ + " mUidTraffic=" + mUidTraffic
+ " }";
}
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
+ public static final @NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
return new BluetoothActivityEnergyInfo(in);
@@ -87,9 +107,8 @@
}
};
-
+ /** @hide */
@Override
- @SuppressWarnings("unchecked")
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mTimestamp);
out.writeInt(mBluetoothStackState);
@@ -97,17 +116,21 @@
out.writeLong(mControllerRxTimeMs);
out.writeLong(mControllerIdleTimeMs);
out.writeLong(mControllerEnergyUsed);
- out.writeTypedArray(mUidTraffic, flags);
+ out.writeTypedList(mUidTraffic);
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
/**
- * @return bt stack reported state
+ * Get the Bluetooth stack state associated with the energy info.
+ *
+ * @return one of {@link #BluetoothStackState} states
*/
+ @BluetoothStackState
public int getBluetoothStackState() {
return mBluetoothStackState;
}
@@ -134,7 +157,7 @@
}
/**
- * product of current(mA), voltage(V) and time(ms)
+ * Get the product of current (mA), voltage (V), and time (ms).
*
* @return energy used
*/
@@ -143,22 +166,31 @@
}
/**
- * @return timestamp(real time elapsed in milliseconds since boot) of record creation.
+ * @return timestamp (real time elapsed in milliseconds since boot) of record creation
*/
- public long getTimeStamp() {
+ public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
}
- public UidTraffic[] getUidTraffic() {
+ /**
+ * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}.
+ *
+ * @return current {@link List} of {@link android.bluetooth.UidTraffic}
+ */
+ public @NonNull List<UidTraffic> getUidTraffic() {
+ if (mUidTraffic == null) {
+ return Collections.emptyList();
+ }
return mUidTraffic;
}
- public void setUidTraffic(UidTraffic[] traffic) {
+ /** @hide */
+ public void setUidTraffic(List<UidTraffic> traffic) {
mUidTraffic = traffic;
}
/**
- * @return if the record is valid
+ * @return true if the record Tx time, Rx time, and Idle time are more than 0.
*/
public boolean isValid() {
return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0)
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 9caeb29..c71fcc6 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1186,6 +1186,11 @@
mAttributionSource = attributionSource;
}
+ /** {@hide} */
+ public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) {
+ setAttributionSource(attributionSource);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof BluetoothDevice) {
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index b5df4db..20152f3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -62,15 +62,15 @@
private static final String TAG = "BluetoothManager";
private static final boolean DBG = false;
- private static AttributionSource sAttributionSource = null;
+ private final AttributionSource mAttributionSource;
private final BluetoothAdapter mAdapter;
/**
* @hide
*/
public BluetoothManager(Context context) {
- sAttributionSource = resolveAttributionSource(context);
- mAdapter = BluetoothAdapter.createAdapter(sAttributionSource);
+ mAttributionSource = resolveAttributionSource(context);
+ mAdapter = BluetoothAdapter.createAdapter(mAttributionSource);
}
/** {@hide} */
@@ -79,9 +79,6 @@
if (context != null) {
res = context.getAttributionSource();
}
- else if (sAttributionSource != null) {
- return sAttributionSource;
- }
if (res == null) {
res = ActivityThread.currentAttributionSource();
}
@@ -201,8 +198,8 @@
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) return devices;
devices = Attributable.setAttributionSource(
- iGatt.getDevicesMatchingConnectionStates(states, sAttributionSource),
- sAttributionSource);
+ iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource),
+ mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java
index 2ee786a..9982fa61 100644
--- a/core/java/android/bluetooth/UidTraffic.java
+++ b/core/java/android/bluetooth/UidTraffic.java
@@ -15,6 +15,7 @@
*/
package android.bluetooth;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,27 +24,27 @@
*
* @hide
*/
-public class UidTraffic implements Cloneable, Parcelable {
+@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+public final class UidTraffic implements Cloneable, Parcelable {
private final int mAppUid;
private long mRxBytes;
private long mTxBytes;
- public UidTraffic(int appUid) {
- mAppUid = appUid;
- }
-
+ /** @hide */
public UidTraffic(int appUid, long rx, long tx) {
mAppUid = appUid;
mRxBytes = rx;
mTxBytes = tx;
}
- UidTraffic(Parcel in) {
+ /** @hide */
+ private UidTraffic(Parcel in) {
mAppUid = in.readInt();
mRxBytes = in.readLong();
mTxBytes = in.readLong();
}
+ /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mAppUid);
@@ -51,44 +52,60 @@
dest.writeLong(mTxBytes);
}
+ /** @hide */
public void setRxBytes(long bytes) {
mRxBytes = bytes;
}
+ /** @hide */
public void setTxBytes(long bytes) {
mTxBytes = bytes;
}
+ /** @hide */
public void addRxBytes(long bytes) {
mRxBytes += bytes;
}
+ /** @hide */
public void addTxBytes(long bytes) {
mTxBytes += bytes;
}
+ /**
+ * @return corresponding app Uid
+ */
public int getUid() {
return mAppUid;
}
+ /**
+ * @return rx bytes count
+ */
public long getRxBytes() {
return mRxBytes;
}
+ /**
+ * @return tx bytes count
+ */
public long getTxBytes() {
return mTxBytes;
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
@Override
public UidTraffic clone() {
return new UidTraffic(mAppUid, mRxBytes, mTxBytes);
}
+ /** @hide */
@Override
public String toString() {
return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes="
diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java
index 6381f55..ed50b09 100644
--- a/core/java/android/bluetooth/le/BluetoothLeUtils.java
+++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java
@@ -24,6 +24,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.UUID;
/**
* Helper class for Bluetooth LE utils.
@@ -137,4 +138,21 @@
}
}
+ /**
+ * Compares two UUIDs with a UUID mask.
+ *
+ * @param data first {@link #UUID} to compare.
+ * @param uuid second {@link #UUID} to compare.
+ * @param mask mask {@link #UUID}.
+ * @return true if both UUIDs are equals when masked, false otherwise.
+ */
+ static boolean maskedEquals(UUID data, UUID uuid, UUID mask) {
+ if (mask == null) {
+ return Objects.equals(data, uuid);
+ }
+ return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ && (data.getMostSignificantBits() & mask.getMostSignificantBits())
+ == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
+ }
}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 8ff0181..b059193 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -28,8 +28,6 @@
import android.os.ParcelUuid;
import android.os.Parcelable;
-import com.android.internal.util.BitUtils;
-
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -448,7 +446,7 @@
// Check if the uuid pattern matches the particular service uuid.
private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
- return BitUtils.maskedEquals(data, uuid, mask);
+ return BluetoothLeUtils.maskedEquals(data, uuid, mask);
}
/**
@@ -478,7 +476,7 @@
// Check if the solicitation uuid pattern matches the particular service solicitation uuid.
private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid,
UUID solicitationUuidMask, UUID data) {
- return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask);
+ return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask);
}
// Check whether the data pattern matches the parsed data.
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 5e2340c..ef5f84c 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -22,7 +22,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.ScanFilter;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.wifi.ScanResult;
import android.os.Build;
@@ -30,9 +29,13 @@
import android.os.Parcelable;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
import java.util.regex.Pattern;
/** @hide */
@@ -73,12 +76,19 @@
static boolean matchesServiceUuid(ParcelUuid serviceUuid, ParcelUuid serviceUuidMask,
BluetoothDevice device) {
- ParcelUuid[] uuids = device.getUuids();
- final boolean result = serviceUuid == null ||
- ScanFilter.matchesServiceUuids(
- serviceUuid,
- serviceUuidMask,
- uuids == null ? Collections.emptyList() : Arrays.asList(uuids));
+ boolean result = false;
+ List<ParcelUuid> deviceUuids = device.getUuids() == null
+ ? Collections.emptyList() : Arrays.asList(device.getUuids());
+ if (serviceUuid == null) {
+ result = true;
+ } else {
+ for (ParcelUuid parcelUuid : deviceUuids) {
+ UUID uuidMask = serviceUuidMask == null ? null : serviceUuidMask.getUuid();
+ if (uuidsMaskedEquals(parcelUuid.getUuid(), serviceUuid.getUuid(), uuidMask)) {
+ result = true;
+ }
+ }
+ }
if (DEBUG) debugLogMatchResult(result, device, serviceUuid);
return result;
}
@@ -143,4 +153,23 @@
throw new IllegalArgumentException("Unknown device type: " + device);
}
}
+
+ /**
+ * Compares two {@link #UUID} with a {@link #UUID} mask.
+ *
+ * @param data first {@link #UUID}.
+ * @param uuid second {@link #UUID}.
+ * @param mask mask {@link #UUID}.
+ * @return true if both UUIDs are equals when masked, false otherwise.
+ */
+ @VisibleForTesting
+ public static boolean uuidsMaskedEquals(UUID data, UUID uuid, UUID mask) {
+ if (mask == null) {
+ return Objects.equals(data, uuid);
+ }
+ return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ && (data.getMostSignificantBits() & mask.getMostSignificantBits())
+ == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
+ }
}
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 828d482..58898cc 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -75,7 +75,7 @@
String renameSuffix, int renameBytesFrom, int renameBytesLength,
int renameNameFrom, int renameNameLength, boolean renameBytesReverseOrder) {
mNamePattern = namePattern;
- mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
+ mScanFilter = ObjectUtils.firstNotNull(scanFilter, new ScanFilter.Builder().build());
mRawDataFilter = rawDataFilter;
mRawDataFilterMask = rawDataFilterMask;
mRenamePrefix = renamePrefix;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2fd437d..d811040 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -31,6 +31,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.AppGlobals;
+import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -11461,6 +11462,16 @@
if (fromProtectedComponent) {
mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
}
+
+ // Special attribution fix-up logic for any BluetoothDevice extras
+ // passed via Bluetooth intents
+ if (mAction != null && mAction.startsWith("android.bluetooth.")
+ && hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
+ final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device != null) {
+ device.prepareToEnterProcess(source);
+ }
+ }
}
/** @hide */
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index c7f92c9..660368a 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -2,11 +2,9 @@
per-file Context.java = *
per-file ContextWrapper.java = *
per-file Content* = file:/services/core/java/com/android/server/am/OWNERS
-per-file IntentFilter.java = toddke@google.com
-per-file IntentFilter.java = patb@google.com
+per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS
per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file Intent.java = toddke@google.com
-per-file Intent.java = patb@google.com
+per-file Intent.java = file:/PACKAGE_MANAGER_OWNERS
per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file Intent.java = file:/services/core/java/com/android/server/am/OWNERS
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 1d07a03..eb8f43e 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -220,8 +220,10 @@
String networkId = null;
boolean roaming = !snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- boolean metered = !snapshot.getNetworkCapabilities().hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ boolean metered = !(snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ || snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED));
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 08f75df..74506da 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -160,19 +160,19 @@
}
/**
- * Template to match cellular networks with the given IMSI and {@code ratType}.
- * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
- * See {@code TelephonyManager.NETWORK_TYPE_*}.
+ * Template to match cellular networks with the given IMSI, {@code ratType} and
+ * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when
+ * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}.
*/
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
- @NetworkType int ratType) {
+ @NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@@ -305,6 +305,7 @@
}
}
+ // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -312,9 +313,14 @@
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
- this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
+ // to metered networks. It is now possible to match mobile with any meteredness, but
+ // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
+ //constructor passes METERED_YES for these types.
+ this(matchRule, subscriberId, matchSubscriberIds, networkId,
+ (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
+ : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
// TODO: Remove it after updating all of the caller.
@@ -589,11 +595,7 @@
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- // Only metered mobile network would be matched regardless of metered filter.
- // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
- // TODO: Respect metered filter and remove mMetered condition.
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
@@ -707,8 +709,7 @@
if (ident.mType == TYPE_WIMAX) {
return true;
} else {
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && matchesCollapsedRatType(ident);
+ return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
}
}
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index f6852e6..0eb4cf3 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -17,16 +17,26 @@
package android.net;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.sntp.Duration64;
+import android.net.sntp.Timestamp64;
import android.os.SystemClock;
import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.TrafficStatsConstants;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.Arrays;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Random;
+import java.util.function.Supplier;
/**
* {@hide}
@@ -60,17 +70,21 @@
private static final int NTP_STRATUM_DEATH = 0;
private static final int NTP_STRATUM_MAX = 15;
- // Number of seconds between Jan 1, 1900 and Jan 1, 1970
- // 70 years plus 17 leap days
- private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
+ // The source of the current system clock time, replaceable for testing.
+ private final Supplier<Instant> mSystemTimeSupplier;
- // system time computed from NTP server response
+ private final Random mRandom;
+
+ // The last offset calculated from an NTP server response
+ private long mClockOffset;
+
+ // The last system time computed from an NTP server response
private long mNtpTime;
- // value of SystemClock.elapsedRealtime() corresponding to mNtpTime
+ // The value of SystemClock.elapsedRealtime() corresponding to mNtpTime / mClockOffset
private long mNtpTimeReference;
- // round trip time in milliseconds
+ // The round trip (network) time in milliseconds
private long mRoundTripTime;
private static class InvalidServerReplyException extends Exception {
@@ -81,6 +95,13 @@
@UnsupportedAppUsage
public SntpClient() {
+ this(Instant::now, defaultRandom());
+ }
+
+ @VisibleForTesting
+ public SntpClient(Supplier<Instant> systemTimeSupplier, Random random) {
+ mSystemTimeSupplier = Objects.requireNonNull(systemTimeSupplier);
+ mRandom = Objects.requireNonNull(random);
}
/**
@@ -126,9 +147,13 @@
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
// get current time and write it to the request packet
- final long requestTime = System.currentTimeMillis();
+ final Instant requestTime = mSystemTimeSupplier.get();
+ final Timestamp64 requestTimestamp = Timestamp64.fromInstant(requestTime);
+
+ final Timestamp64 randomizedRequestTimestamp =
+ requestTimestamp.randomizeSubMillis(mRandom);
final long requestTicks = SystemClock.elapsedRealtime();
- writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
+ writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, randomizedRequestTimestamp);
socket.send(request);
@@ -136,42 +161,44 @@
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
final long responseTicks = SystemClock.elapsedRealtime();
- final long responseTime = requestTime + (responseTicks - requestTicks);
+ final Instant responseTime = requestTime.plusMillis(responseTicks - requestTicks);
+ final Timestamp64 responseTimestamp = Timestamp64.fromInstant(responseTime);
// extract the results
final byte leap = (byte) ((buffer[0] >> 6) & 0x3);
final byte mode = (byte) (buffer[0] & 0x7);
final int stratum = (int) (buffer[1] & 0xff);
- final long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
- final long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
- final long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
- final long referenceTime = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
+ final Timestamp64 referenceTimestamp = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
+ final Timestamp64 originateTimestamp = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
+ final Timestamp64 receiveTimestamp = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
+ final Timestamp64 transmitTimestamp = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
/* Do validation according to RFC */
- // TODO: validate originateTime == requestTime.
- checkValidServerReply(leap, mode, stratum, transmitTime, referenceTime);
+ checkValidServerReply(leap, mode, stratum, transmitTimestamp, referenceTimestamp,
+ randomizedRequestTimestamp, originateTimestamp);
- long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
- // receiveTime = originateTime + transit + skew
- // responseTime = transmitTime + transit - skew
- // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
- // = ((originateTime + transit + skew - originateTime) +
- // (transmitTime - (transmitTime + transit - skew)))/2
- // = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
- // = (transit + skew - transit + skew)/2
- // = (2 * skew)/2 = skew
- long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
- EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset);
+ long totalTransactionDurationMillis = responseTicks - requestTicks;
+ long serverDurationMillis =
+ Duration64.between(receiveTimestamp, transmitTimestamp).toDuration().toMillis();
+ long roundTripTimeMillis = totalTransactionDurationMillis - serverDurationMillis;
+
+ Duration clockOffsetDuration = calculateClockOffset(requestTimestamp,
+ receiveTimestamp, transmitTimestamp, responseTimestamp);
+ long clockOffsetMillis = clockOffsetDuration.toMillis();
+
+ EventLogTags.writeNtpSuccess(
+ address.toString(), roundTripTimeMillis, clockOffsetMillis);
if (DBG) {
- Log.d(TAG, "round trip: " + roundTripTime + "ms, " +
- "clock offset: " + clockOffset + "ms");
+ Log.d(TAG, "round trip: " + roundTripTimeMillis + "ms, "
+ + "clock offset: " + clockOffsetMillis + "ms");
}
// save our results - use the times on this side of the network latency
// (response rather than request time)
- mNtpTime = responseTime + clockOffset;
+ mClockOffset = clockOffsetMillis;
+ mNtpTime = responseTime.plus(clockOffsetDuration).toEpochMilli();
mNtpTimeReference = responseTicks;
- mRoundTripTime = roundTripTime;
+ mRoundTripTime = roundTripTimeMillis;
} catch (Exception e) {
EventLogTags.writeNtpFailure(address.toString(), e.toString());
if (DBG) Log.d(TAG, "request time failed: " + e);
@@ -186,6 +213,28 @@
return true;
}
+ /** Performs the NTP clock offset calculation. */
+ @VisibleForTesting
+ public static Duration calculateClockOffset(Timestamp64 clientRequestTimestamp,
+ Timestamp64 serverReceiveTimestamp, Timestamp64 serverTransmitTimestamp,
+ Timestamp64 clientResponseTimestamp) {
+ // According to RFC4330:
+ // t is the system clock offset (the adjustment we are trying to find)
+ // t = ((T2 - T1) + (T3 - T4)) / 2
+ //
+ // Which is:
+ // t = (([server]receiveTimestamp - [client]requestTimestamp)
+ // + ([server]transmitTimestamp - [client]responseTimestamp)) / 2
+ //
+ // See the NTP spec and tests: the numeric types used are deliberate:
+ // + Duration64.between() uses 64-bit arithmetic (32-bit for the seconds).
+ // + plus() / dividedBy() use Duration, which isn't the double precision floating point
+ // used in NTPv4, but is good enough.
+ return Duration64.between(clientRequestTimestamp, serverReceiveTimestamp)
+ .plus(Duration64.between(clientResponseTimestamp, serverTransmitTimestamp))
+ .dividedBy(2);
+ }
+
@Deprecated
@UnsupportedAppUsage
public boolean requestTime(String host, int timeout) {
@@ -194,6 +243,14 @@
}
/**
+ * Returns the offset calculated to apply to the client clock to arrive at {@link #getNtpTime()}
+ */
+ @VisibleForTesting
+ public long getClockOffset() {
+ return mClockOffset;
+ }
+
+ /**
* Returns the time computed from the NTP transaction.
*
* @return time value computed from NTP server response.
@@ -225,8 +282,9 @@
}
private static void checkValidServerReply(
- byte leap, byte mode, int stratum, long transmitTime, long referenceTime)
- throws InvalidServerReplyException {
+ byte leap, byte mode, int stratum, Timestamp64 transmitTimestamp,
+ Timestamp64 referenceTimestamp, Timestamp64 randomizedRequestTimestamp,
+ Timestamp64 originateTimestamp) throws InvalidServerReplyException {
if (leap == NTP_LEAP_NOSYNC) {
throw new InvalidServerReplyException("unsynchronized server");
}
@@ -236,73 +294,68 @@
if ((stratum == NTP_STRATUM_DEATH) || (stratum > NTP_STRATUM_MAX)) {
throw new InvalidServerReplyException("untrusted stratum: " + stratum);
}
- if (transmitTime == 0) {
- throw new InvalidServerReplyException("zero transmitTime");
+ if (!randomizedRequestTimestamp.equals(originateTimestamp)) {
+ throw new InvalidServerReplyException(
+ "originateTimestamp != randomizedRequestTimestamp");
}
- if (referenceTime == 0) {
- throw new InvalidServerReplyException("zero reference timestamp");
+ if (transmitTimestamp.equals(Timestamp64.ZERO)) {
+ throw new InvalidServerReplyException("zero transmitTimestamp");
+ }
+ if (referenceTimestamp.equals(Timestamp64.ZERO)) {
+ throw new InvalidServerReplyException("zero referenceTimestamp");
}
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
- private long read32(byte[] buffer, int offset) {
- byte b0 = buffer[offset];
- byte b1 = buffer[offset+1];
- byte b2 = buffer[offset+2];
- byte b3 = buffer[offset+3];
+ private long readUnsigned32(byte[] buffer, int offset) {
+ int i0 = buffer[offset++] & 0xFF;
+ int i1 = buffer[offset++] & 0xFF;
+ int i2 = buffer[offset++] & 0xFF;
+ int i3 = buffer[offset] & 0xFF;
- // convert signed bytes to unsigned values
- int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
- int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
- int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
- int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
-
- return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
+ int bits = (i0 << 24) | (i1 << 16) | (i2 << 8) | i3;
+ return bits & 0xFFFF_FFFFL;
}
/**
- * Reads the NTP time stamp at the given offset in the buffer and returns
- * it as a system time (milliseconds since January 1, 1970).
+ * Reads the NTP time stamp from the given offset in the buffer.
*/
- private long readTimeStamp(byte[] buffer, int offset) {
- long seconds = read32(buffer, offset);
- long fraction = read32(buffer, offset + 4);
- // Special case: zero means zero.
- if (seconds == 0 && fraction == 0) {
- return 0;
- }
- return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
+ private Timestamp64 readTimeStamp(byte[] buffer, int offset) {
+ long seconds = readUnsigned32(buffer, offset);
+ int fractionBits = (int) readUnsigned32(buffer, offset + 4);
+ return Timestamp64.fromComponents(seconds, fractionBits);
}
/**
- * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp
- * at the given offset in the buffer.
+ * Writes the NTP time stamp at the given offset in the buffer.
*/
- private void writeTimeStamp(byte[] buffer, int offset, long time) {
- // Special case: zero means zero.
- if (time == 0) {
- Arrays.fill(buffer, offset, offset + 8, (byte) 0x00);
- return;
- }
-
- long seconds = time / 1000L;
- long milliseconds = time - seconds * 1000L;
- seconds += OFFSET_1900_TO_1970;
-
+ private void writeTimeStamp(byte[] buffer, int offset, Timestamp64 timestamp) {
+ long seconds = timestamp.getEraSeconds();
// write seconds in big endian format
- buffer[offset++] = (byte)(seconds >> 24);
- buffer[offset++] = (byte)(seconds >> 16);
- buffer[offset++] = (byte)(seconds >> 8);
- buffer[offset++] = (byte)(seconds >> 0);
+ buffer[offset++] = (byte) (seconds >>> 24);
+ buffer[offset++] = (byte) (seconds >>> 16);
+ buffer[offset++] = (byte) (seconds >>> 8);
+ buffer[offset++] = (byte) (seconds);
- long fraction = milliseconds * 0x100000000L / 1000L;
+ int fractionBits = timestamp.getFractionBits();
// write fraction in big endian format
- buffer[offset++] = (byte)(fraction >> 24);
- buffer[offset++] = (byte)(fraction >> 16);
- buffer[offset++] = (byte)(fraction >> 8);
- // low order bits should be random data
- buffer[offset++] = (byte)(Math.random() * 255.0);
+ buffer[offset++] = (byte) (fractionBits >>> 24);
+ buffer[offset++] = (byte) (fractionBits >>> 16);
+ buffer[offset++] = (byte) (fractionBits >>> 8);
+ buffer[offset] = (byte) (fractionBits);
+ }
+
+ private static Random defaultRandom() {
+ Random random;
+ try {
+ random = SecureRandom.getInstanceStrong();
+ } catch (NoSuchAlgorithmException e) {
+ // This should never happen.
+ Slog.wtf(TAG, "Unable to access SecureRandom", e);
+ random = new Random(System.currentTimeMillis());
+ }
+ return random;
}
}
diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING
index 8c13ef9..a379c33 100644
--- a/core/java/android/net/TEST_MAPPING
+++ b/core/java/android/net/TEST_MAPPING
@@ -16,5 +16,24 @@
{
"path": "frameworks/opt/net/wifi"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.net"
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
]
}
diff --git a/core/java/android/net/sntp/Duration64.java b/core/java/android/net/sntp/Duration64.java
new file mode 100644
index 0000000..7f29cdb
--- /dev/null
+++ b/core/java/android/net/sntp/Duration64.java
@@ -0,0 +1,141 @@
+/*
+ * 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 android.net.sntp;
+
+import java.time.Duration;
+
+/**
+ * A type similar to {@link Timestamp64} but used when calculating the difference between two
+ * timestamps. As such, it is a signed type, but still uses 64-bits in total and so can only
+ * represent half the magnitude of {@link Timestamp64}.
+ *
+ * <p>See <a href="https://www.eecis.udel.edu/~mills/time.html">4. Time Difference Calculations</a>.
+ *
+ * @hide
+ */
+public final class Duration64 {
+
+ public static final Duration64 ZERO = new Duration64(0);
+ private final long mBits;
+
+ private Duration64(long bits) {
+ this.mBits = bits;
+ }
+
+ /**
+ * Returns the difference between two 64-bit NTP timestamps as a {@link Duration64}, as
+ * described in the NTP spec. The times represented by the timestamps have to be within {@link
+ * Timestamp64#MAX_SECONDS_IN_ERA} (~68 years) of each other for the calculation to produce a
+ * correct answer.
+ */
+ public static Duration64 between(Timestamp64 startInclusive, Timestamp64 endExclusive) {
+ long oneBits = (startInclusive.getEraSeconds() << 32)
+ | (startInclusive.getFractionBits() & 0xFFFF_FFFFL);
+ long twoBits = (endExclusive.getEraSeconds() << 32)
+ | (endExclusive.getFractionBits() & 0xFFFF_FFFFL);
+ long resultBits = twoBits - oneBits;
+ return new Duration64(resultBits);
+ }
+
+ /**
+ * Add two {@link Duration64} instances together. This performs the calculation in {@link
+ * Duration} and returns a {@link Duration} to increase the magnitude of accepted arguments,
+ * since {@link Duration64} only supports signed 32-bit seconds. The use of {@link Duration}
+ * limits precision to nanoseconds.
+ */
+ public Duration plus(Duration64 other) {
+ // From https://www.eecis.udel.edu/~mills/time.html:
+ // "The offset and delay calculations require sums and differences of these raw timestamp
+ // differences that can span no more than from 34 years in the future to 34 years in the
+ // past without overflow. This is a fundamental limitation in 64-bit integer calculations.
+ //
+ // In the NTPv4 reference implementation, all calculations involving offset and delay values
+ // use 64-bit floating double arithmetic, with the exception of raw timestamp subtraction,
+ // as mentioned above. The raw timestamp differences are then converted to 64-bit floating
+ // double format without loss of precision or chance of overflow in subsequent
+ // calculations."
+ //
+ // Here, we use Duration instead, which provides sufficient range, but loses precision below
+ // nanos.
+ return this.toDuration().plus(other.toDuration());
+ }
+
+ /**
+ * Returns a {@link Duration64} equivalent of the supplied duration, if the magnitude can be
+ * represented. Because {@link Duration64} uses a fixed point type for sub-second values it
+ * cannot represent all nanosecond values precisely and so the conversion can be lossy.
+ *
+ * @throws IllegalArgumentException if the supplied duration is too big to be represented
+ */
+ public static Duration64 fromDuration(Duration duration) {
+ long seconds = duration.getSeconds();
+ if (seconds < Integer.MIN_VALUE || seconds > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException();
+ }
+ long bits = (seconds << 32)
+ | (Timestamp64.nanosToFractionBits(duration.getNano()) & 0xFFFF_FFFFL);
+ return new Duration64(bits);
+ }
+
+ /**
+ * Returns a {@link Duration} equivalent of this duration. Because {@link Duration64} uses a
+ * fixed point type for sub-second values it can values smaller than nanosecond precision and so
+ * the conversion can be lossy.
+ */
+ public Duration toDuration() {
+ int seconds = getSeconds();
+ int nanos = getNanos();
+ return Duration.ofSeconds(seconds, nanos);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Duration64 that = (Duration64) o;
+ return mBits == that.mBits;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(mBits);
+ }
+
+ @Override
+ public String toString() {
+ Duration duration = toDuration();
+ return Long.toHexString(mBits)
+ + "(" + duration.getSeconds() + "s " + duration.getNano() + "ns)";
+ }
+
+ /**
+ * Returns the <em>signed</em> seconds in this duration.
+ */
+ public int getSeconds() {
+ return (int) (mBits >> 32);
+ }
+
+ /**
+ * Returns the <em>unsigned</em> nanoseconds in this duration (truncated).
+ */
+ public int getNanos() {
+ return Timestamp64.fractionBitsToNanos((int) (mBits & 0xFFFF_FFFFL));
+ }
+}
diff --git a/core/java/android/net/sntp/Timestamp64.java b/core/java/android/net/sntp/Timestamp64.java
new file mode 100644
index 0000000..8ddfd77
--- /dev/null
+++ b/core/java/android/net/sntp/Timestamp64.java
@@ -0,0 +1,188 @@
+/*
+ * 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 android.net.sntp;
+
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Random;
+
+/**
+ * The 64-bit type ("timestamp") that NTP uses to represent a point in time. It only holds the
+ * lowest 32-bits of the number of seconds since 1900-01-01 00:00:00. Consequently, to turn an
+ * instance into an unambiguous point in time the era number must be known. Era zero runs from
+ * 1900-01-01 00:00:00 to a date in 2036.
+ *
+ * It stores sub-second values using a 32-bit fixed point type, so it can resolve values smaller
+ * than a nanosecond, but is imprecise (i.e. it truncates).
+ *
+ * See also <a href=https://www.eecis.udel.edu/~mills/y2k.html>NTP docs</a>.
+ *
+ * @hide
+ */
+public final class Timestamp64 {
+
+ public static final Timestamp64 ZERO = fromComponents(0, 0);
+ static final int SUB_MILLIS_BITS_TO_RANDOMIZE = 32 - 10;
+
+ // Number of seconds between Jan 1, 1900 and Jan 1, 1970
+ // 70 years plus 17 leap days
+ static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
+ static final long MAX_SECONDS_IN_ERA = 0xFFFF_FFFFL;
+ static final long SECONDS_IN_ERA = MAX_SECONDS_IN_ERA + 1;
+
+ static final int NANOS_PER_SECOND = 1_000_000_000;
+
+ /** Creates a {@link Timestamp64} from the seconds and fraction components. */
+ public static Timestamp64 fromComponents(long eraSeconds, int fractionBits) {
+ return new Timestamp64(eraSeconds, fractionBits);
+ }
+
+ /** Creates a {@link Timestamp64} by decoding a string in the form "e4dc720c.4d4fc9eb". */
+ public static Timestamp64 fromString(String string) {
+ final int requiredLength = 17;
+ if (string.length() != requiredLength || string.charAt(8) != '.') {
+ throw new IllegalArgumentException(string);
+ }
+ String eraSecondsString = string.substring(0, 8);
+ String fractionString = string.substring(9);
+ long eraSeconds = Long.parseLong(eraSecondsString, 16);
+
+ // Use parseLong() because the type is unsigned. Integer.parseInt() will reject 0x70000000
+ // or above as being out of range.
+ long fractionBitsAsLong = Long.parseLong(fractionString, 16);
+ if (fractionBitsAsLong < 0 || fractionBitsAsLong > 0xFFFFFFFFL) {
+ throw new IllegalArgumentException("Invalid fractionBits:" + fractionString);
+ }
+ return new Timestamp64(eraSeconds, (int) fractionBitsAsLong);
+ }
+
+ /**
+ * Converts an {@link Instant} into a {@link Timestamp64}. This is lossy: Timestamp64 only
+ * contains the number of seconds in a given era, but the era is not stored. Also, sub-second
+ * values are not stored precisely.
+ */
+ public static Timestamp64 fromInstant(Instant instant) {
+ long ntpEraSeconds = instant.getEpochSecond() + OFFSET_1900_TO_1970;
+ if (ntpEraSeconds < 0) {
+ ntpEraSeconds = SECONDS_IN_ERA - (-ntpEraSeconds % SECONDS_IN_ERA);
+ }
+ ntpEraSeconds %= SECONDS_IN_ERA;
+
+ long nanos = instant.getNano();
+ int fractionBits = nanosToFractionBits(nanos);
+
+ return new Timestamp64(ntpEraSeconds, fractionBits);
+ }
+
+ private final long mEraSeconds;
+ private final int mFractionBits;
+
+ private Timestamp64(long eraSeconds, int fractionBits) {
+ if (eraSeconds < 0 || eraSeconds > MAX_SECONDS_IN_ERA) {
+ throw new IllegalArgumentException(
+ "Invalid parameters. seconds=" + eraSeconds + ", fraction=" + fractionBits);
+ }
+ this.mEraSeconds = eraSeconds;
+ this.mFractionBits = fractionBits;
+ }
+
+ /** Returns the number of seconds in the NTP era. */
+ public long getEraSeconds() {
+ return mEraSeconds;
+ }
+
+ /** Returns the fraction of a second as 32-bit, unsigned fixed-point bits. */
+ public int getFractionBits() {
+ return mFractionBits;
+ }
+
+ @Override
+ public String toString() {
+ return TextUtils.formatSimple("%08x.%08x", mEraSeconds, mFractionBits);
+ }
+
+ /** Returns the instant represented by this value in the specified NTP era. */
+ public Instant toInstant(int ntpEra) {
+ long secondsSinceEpoch = mEraSeconds - OFFSET_1900_TO_1970;
+ secondsSinceEpoch += ntpEra * SECONDS_IN_ERA;
+
+ int nanos = fractionBitsToNanos(mFractionBits);
+ return Instant.ofEpochSecond(secondsSinceEpoch, nanos);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Timestamp64 that = (Timestamp64) o;
+ return mEraSeconds == that.mEraSeconds && mFractionBits == that.mFractionBits;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEraSeconds, mFractionBits);
+ }
+
+ static int fractionBitsToNanos(int fractionBits) {
+ long fractionBitsLong = fractionBits & 0xFFFF_FFFFL;
+ return (int) ((fractionBitsLong * NANOS_PER_SECOND) >>> 32);
+ }
+
+ static int nanosToFractionBits(long nanos) {
+ if (nanos > NANOS_PER_SECOND) {
+ throw new IllegalArgumentException();
+ }
+ return (int) ((nanos << 32) / NANOS_PER_SECOND);
+ }
+
+ /**
+ * Randomizes the fraction bits that represent sub-millisecond values. i.e. the randomization
+ * won't change the number of milliseconds represented after truncation. This is used to
+ * implement the part of the NTP spec that calls for clients with millisecond accuracy clocks
+ * to send randomized LSB values rather than zeros.
+ */
+ public Timestamp64 randomizeSubMillis(Random random) {
+ int randomizedFractionBits =
+ randomizeLowestBits(random, this.mFractionBits, SUB_MILLIS_BITS_TO_RANDOMIZE);
+ return new Timestamp64(mEraSeconds, randomizedFractionBits);
+ }
+
+ /**
+ * Randomizes the specified number of LSBs in {@code value} by using replacement bits from
+ * {@code Random.getNextInt()}.
+ */
+ @VisibleForTesting
+ public static int randomizeLowestBits(Random random, int value, int bitsToRandomize) {
+ if (bitsToRandomize < 1 || bitsToRandomize >= Integer.SIZE) {
+ // There's no point in randomizing all bits or none of the bits.
+ throw new IllegalArgumentException(Integer.toString(bitsToRandomize));
+ }
+
+ int upperBitMask = 0xFFFF_FFFF << bitsToRandomize;
+ int lowerBitMask = ~upperBitMask;
+
+ int randomValue = random.nextInt();
+ return (value & upperBitMask) | (randomValue & lowerBitMask);
+ }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 635f581..b677b69 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -313,7 +313,7 @@
* @hide
*/
@CriticalNative
- public static final native boolean isHandlingTransaction();
+ public static final native boolean isDirectlyHandlingTransaction();
/**
* Return the Linux uid assigned to the process that sent the transaction
@@ -323,7 +323,7 @@
* executing an incoming transaction.
*/
public static final int getCallingUidOrThrow() {
- if (!isHandlingTransaction()) {
+ if (!isDirectlyHandlingTransaction()) {
throw new IllegalStateException(
"Thread is not in a binder transcation");
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a0f8615..eda3699 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5207,7 +5207,7 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public static @NonNull Map<String, List<ContentValues>> queryRawContactEntity(
- @NonNull Context context, long contactId) {
+ @NonNull ContentResolver contentResolver, long contactId) {
Uri uri = RawContactsEntity.CONTENT_URI;
long realContactId = contactId;
@@ -5225,7 +5225,7 @@
final String selection = Data.CONTACT_ID + "=?";
final String[] selectionArgs = new String[] {String.valueOf(realContactId)};
- entityIterator = RawContacts.newEntityIterator(context.getContentResolver().query(
+ entityIterator = RawContacts.newEntityIterator(contentResolver.query(
uri, null, selection, selectionArgs, null));
if (entityIterator == null) {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f5f5eb8..25e3a4f 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -298,6 +298,14 @@
public static final String NAMESPACE_NETD_NATIVE = "netd_native";
/**
+ * Namespace for all Android NNAPI related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
+
+ /**
* Namespace for features related to the Package Manager Service.
*
* @hide
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 3f3c9bd..7c39118 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -25,17 +25,22 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.apex.ApexInfo;
+import com.android.apex.XmlParser;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfigParser.OverlayPartition;
import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.TriConsumer;
import java.io.File;
+import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
-import java.util.function.BiConsumer;
+import java.util.List;
import java.util.function.Supplier;
/**
@@ -73,7 +78,7 @@
public interface PackageProvider {
/** Performs the given action for each package. */
- void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p);
+ void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p);
}
private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
@@ -115,6 +120,8 @@
p)));
}
+ ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions);
+
boolean foundConfigFile = false;
ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null;
@@ -123,7 +130,9 @@
final OverlayPartition partition = partitions.get(i);
final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get();
final ArrayList<ParsedConfiguration> partitionOverlays =
- OverlayConfigParser.getConfigurations(partition, scanner);
+ OverlayConfigParser.getConfigurations(partition, scanner,
+ activeApexesPerPartition.getOrDefault(partition.type,
+ Collections.emptyList()));
if (partitionOverlays != null) {
foundConfigFile = true;
overlays.addAll(partitionOverlays);
@@ -145,7 +154,8 @@
// Filter out overlays not present in the partition.
partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos);
for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) {
- if (!partition.containsFile(partitionOverlayInfos.get(j).path)) {
+ if (!partition.containsFile(partitionOverlayInfos.get(j)
+ .getOriginalPartitionPath())) {
partitionOverlayInfos.remove(j);
}
}
@@ -292,16 +302,49 @@
private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos(
@NonNull PackageProvider packageManager) {
final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>();
- packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> {
+ packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem,
+ @Nullable File preInstalledApexPath) -> {
if (p.getOverlayTarget() != null && isSystem) {
overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
- new File(p.getBaseApkPath())));
+ new File(p.getBaseApkPath()), preInstalledApexPath));
}
});
return overlays;
}
+ /** Returns a map of PartitionType to List of active APEX module names. */
+ @NonNull
+ private static ArrayMap<Integer, List<String>> getActiveApexes(
+ @NonNull List<OverlayPartition> partitions) {
+ // An Overlay in an APEX, which is an update of an APEX in a given partition,
+ // is considered as belonging to that partition.
+ ArrayMap<Integer, List<String>> result = new ArrayMap<>();
+ for (OverlayPartition partition : partitions) {
+ result.put(partition.type, new ArrayList<String>());
+ }
+ // Read from apex-info-list because ApexManager is not accessible to zygote.
+ File apexInfoList = new File("/apex/apex-info-list.xml");
+ if (apexInfoList.exists() && apexInfoList.canRead()) {
+ try (FileInputStream stream = new FileInputStream(apexInfoList)) {
+ List<ApexInfo> apexInfos = XmlParser.readApexInfoList(stream).getApexInfo();
+ for (ApexInfo info : apexInfos) {
+ if (info.getIsActive()) {
+ for (OverlayPartition partition : partitions) {
+ if (partition.containsPath(info.getPreinstalledModulePath())) {
+ result.get(partition.type).add(info.getModuleName());
+ break;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error reading apex-info-list: " + e);
+ }
+ }
+ return result;
+ }
+
/** Represents a single call to idmap create-multiple. */
@VisibleForTesting
public static class IdmapInvocation {
diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java
index a86e595..d48c2e7 100644
--- a/core/java/com/android/internal/content/om/OverlayConfigParser.java
+++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java
@@ -40,6 +40,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
/**
* Responsible for parsing configurations of Runtime Resource Overlays that control mutability,
@@ -192,13 +193,19 @@
*/
@Nullable
static ArrayList<ParsedConfiguration> getConfigurations(
- @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) {
- if (partition.getOverlayFolder() == null) {
- return null;
+ @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner,
+ @NonNull List<String> activeApexes) {
+ if (scanner != null) {
+ if (partition.getOverlayFolder() != null) {
+ scanner.scanDir(partition.getOverlayFolder());
+ }
+ for (String apex : activeApexes) {
+ scanner.scanDir(new File("/apex/" + apex + "/overlay/"));
+ }
}
- if (scanner != null) {
- scanner.scanDir(partition.getOverlayFolder());
+ if (partition.getOverlayFolder() == null) {
+ return null;
}
final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME);
diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java
index 6b5cb8d..138d1ce 100644
--- a/core/java/com/android/internal/content/om/OverlayScanner.java
+++ b/core/java/com/android/internal/content/om/OverlayScanner.java
@@ -47,23 +47,38 @@
public final boolean isStatic;
public final int priority;
public final File path;
+ @Nullable public final File preInstalledApexPath;
public ParsedOverlayInfo(String packageName, String targetPackageName,
- int targetSdkVersion, boolean isStatic, int priority, File path) {
+ int targetSdkVersion, boolean isStatic, int priority, File path,
+ @Nullable File preInstalledApexPath) {
this.packageName = packageName;
this.targetPackageName = targetPackageName;
this.targetSdkVersion = targetSdkVersion;
this.isStatic = isStatic;
this.priority = priority;
this.path = path;
+ this.preInstalledApexPath = preInstalledApexPath;
}
@Override
public String toString() {
return getClass().getSimpleName() + String.format("{packageName=%s"
+ ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s"
- + ", priority=%s, path=%s}",
- packageName, targetPackageName, targetSdkVersion, isStatic, priority, path);
+ + ", priority=%s, path=%s, preInstalledApexPath=%s}",
+ packageName, targetPackageName, targetSdkVersion, isStatic,
+ priority, path, preInstalledApexPath);
+ }
+
+ /**
+ * Retrieves the path of the overlay in its original installation partition.
+ *
+ * An Overlay in an APEX, which is an update of an APEX in a given partition,
+ * is considered as belonging to that partition.
+ */
+ @NonNull
+ public File getOriginalPartitionPath() {
+ return preInstalledApexPath != null ? preInstalledApexPath : path;
}
}
@@ -138,6 +153,6 @@
return apkLite.getTargetPackageName() == null ? null :
new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(),
apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(),
- apkLite.getOverlayPriority(), new File(apkLite.getPath()));
+ apkLite.getOverlayPriority(), new File(apkLite.getPath()), null);
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8c63f38..630851d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12143,7 +12143,7 @@
rxTimeMs = info.getControllerRxTimeMillis();
txTimeMs = info.getControllerTxTimeMillis();
energy = info.getControllerEnergyUsed();
- if (info.getUidTraffic() != null) {
+ if (!info.getUidTraffic().isEmpty()) {
for (UidTraffic traffic : info.getUidTraffic()) {
uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
@@ -12294,10 +12294,10 @@
long totalTxBytes = 0;
long totalRxBytes = 0;
- final UidTraffic[] uidTraffic = info.getUidTraffic();
- final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+ final List<UidTraffic> uidTraffic = info.getUidTraffic();
+ final int numUids = uidTraffic.size();
for (int i = 0; i < numUids; i++) {
- final UidTraffic traffic = uidTraffic[i];
+ final UidTraffic traffic = uidTraffic.get(i);
final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(
traffic.getUid());
final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(
@@ -12320,7 +12320,7 @@
if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0
|| leftOverTxTimeMs != 0)) {
for (int i = 0; i < numUids; i++) {
- final UidTraffic traffic = uidTraffic[i];
+ final UidTraffic traffic = uidTraffic.get(i);
final int uid = traffic.getUid();
final long rxBytes =
traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid);
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0d33807..be9aaaf 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -641,7 +641,7 @@
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
bool result;
- status_t err = parcel->hasFileDescriptorsInRange(offset, length, result);
+ status_t err = parcel->hasFileDescriptorsInRange(offset, length, &result);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
return JNI_FALSE;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 793b4eb..61b91dd 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -959,8 +959,7 @@
return IPCThreadState::self()->getCallingUid();
}
-static jboolean android_os_Binder_isHandlingTransaction()
-{
+static jboolean android_os_Binder_isDirectlyHandlingTransaction() {
return getCurrentServingCall() == BinderCallType::BINDER;
}
@@ -1056,6 +1055,7 @@
// ----------------------------------------------------------------------------
+// clang-format off
static const JNINativeMethod gBinderMethods[] = {
/* name, signature, funcPtr */
// @CriticalNative
@@ -1063,7 +1063,7 @@
// @CriticalNative
{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
// @CriticalNative
- { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction },
+ { "isDirectlyHandlingTransaction", "()Z", (void*)android_os_Binder_isDirectlyHandlingTransaction },
// @CriticalNative
{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
// @CriticalNative
@@ -1088,6 +1088,7 @@
{ "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
{ "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
};
+// clang-format on
const char* const kBinderPathName = "android/os/Binder";
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 6f5cc53..40f6e4f 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -138,6 +138,14 @@
return true;
}
+ // Allow Runtime Resource Overlays inside APEXes.
+ static const char* kOverlayPathSuffix = "/overlay";
+ if (android::base::StartsWith(path, kApexPrefix) &&
+ android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) &&
+ android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) {
+ return true;
+ }
+
static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
static const char* kOverlayIdmapSuffix = ".apk@idmap";
if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bd89578..1418dbe 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1976,6 +1976,14 @@
android:label="@string/permlab_uwb_ranging"
android:protectionLevel="dangerous" />
+ <!-- Required to be able to advertise and connect to nearby devices via Wi-Fi.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.NEARBY_WIFI_DEVICES"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_nearby_wifi_devices"
+ android:label="@string/permlab_nearby_wifi_devices"
+ android:protectionLevel="dangerous" />
+
<!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
user from using them until they are unsuspended.
@hide
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 684202b..165dcad 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -28,3 +28,6 @@
# Multiuser
per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
+
+# Car
+per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
\ No newline at end of file
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a99a220..a350d14 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1488,6 +1488,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
<string name="permdesc_uwb_ranging">Allow the app to determine relative position between nearby Ultra-Wideband devices</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]-->
+ <string name="permlab_nearby_wifi_devices">interact with nearby Wi\u2011Fi devices</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
+ <string name="permdesc_nearby_wifi_devices">Allows the app to advertise, connect, and determine the relative position of nearby Wi\u2011Fi devices</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/companiontests/Android.bp b/core/tests/companiontests/Android.bp
new file mode 100644
index 0000000..d31b8f4
--- /dev/null
+++ b/core/tests/companiontests/Android.bp
@@ -0,0 +1,21 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "CompanionTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/companiontests/AndroidManifest.xml b/core/tests/companiontests/AndroidManifest.xml
new file mode 100644
index 0000000..f436d97
--- /dev/null
+++ b/core/tests/companiontests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.companion.tests"
+ android:sharedUserId="android.uid.system" >
+
+ <application >
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="android.companion.CompanionTestRunner"
+ android:targetPackage="com.android.companion.tests"
+ android:label="Companion Tests" />
+
+</manifest>
diff --git a/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java
new file mode 100644
index 0000000..1ddbbd8
--- /dev/null
+++ b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.os.ParcelUuid;
+import android.test.InstrumentationTestCase;
+
+public class BluetoothDeviceFilterUtilsTest extends InstrumentationTestCase {
+ private static final String TAG = "BluetoothDeviceFilterUtilsTest";
+
+ private final ParcelUuid mServiceUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mNonMatchingDeviceUuid =
+ ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMatchingDeviceUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMaskUuid =
+ ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMatchingMaskUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testUuidsMaskedEquals() {
+ assertFalse(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mNonMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMaskUuid.getUuid()));
+
+ assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMaskUuid.getUuid()));
+
+ assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mNonMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMatchingMaskUuid.getUuid()));
+ }
+}
diff --git a/core/tests/companiontests/src/android/companion/CompanionTestRunner.java b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java
new file mode 100644
index 0000000..caa2c68
--- /dev/null
+++ b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation test runner for Companion tests.
+ */
+public class CompanionTestRunner extends InstrumentationTestRunner {
+ private static final String TAG = "CompanionTestRunner";
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(BluetoothDeviceFilterUtilsTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return CompanionTestRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ super.onCreate(arguments);
+ }
+}
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index bf9978c..b400b9b 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -22,7 +22,10 @@
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import android.net.sntp.Duration64;
+import android.net.sntp.Timestamp64;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +41,13 @@
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.Arrays;
+import java.util.Random;
+import java.util.function.Supplier;
@RunWith(AndroidJUnit4.class)
public class SntpClientTest {
@@ -54,41 +63,232 @@
//
// Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20
// Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41
- // Reference Timestamp: 3653932102.507969856 (2015/10/15 14:08:22)
- // Originator Timestamp: 3653932113.576327741 (2015/10/15 14:08:33)
- // Receive Timestamp: 3653932113.581012725 (2015/10/15 14:08:33)
- // Transmit Timestamp: 3653932113.581012725 (2015/10/15 14:08:33)
+ // Reference Timestamp:
+ // d9ca9446.820a5000 / ERA0: 2015-10-15 21:08:22 UTC / ERA1: 2151-11-22 03:36:38 UTC
+ // Originator Timestamp:
+ // d9ca9451.938a3771 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ // Receive Timestamp:
+ // d9ca9451.94bd3fff / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ // Transmit Timestamp:
+ // d9ca9451.94bd4001 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ //
// Originator - Receive Timestamp: +0.004684958
// Originator - Transmit Timestamp: +0.004684958
- private static final String WORKING_VERSION4 =
- "240206ec" +
- "00000165" +
- "000000b2" +
- "ddfd4729" +
- "d9ca9446820a5000" +
- "d9ca9451938a3771" +
- "d9ca945194bd3fff" +
- "d9ca945194bd4001";
+ private static final String LATE_ERA_RESPONSE =
+ "240206ec"
+ + "00000165"
+ + "000000b2"
+ + "ddfd4729"
+ + "d9ca9446820a5000"
+ + "d9ca9451938a3771"
+ + "d9ca945194bd3fff"
+ + "d9ca945194bd4001";
+
+ /** This is the actual UTC time in the server if it is in ERA0 */
+ private static final Instant LATE_ERA0_SERVER_TIME =
+ calculateIdealServerTime("d9ca9451.94bd3fff", "d9ca9451.94bd4001", 0);
+
+ /**
+ * This is the Unix epoch time matches the originate timestamp from {@link #LATE_ERA_RESPONSE}
+ * when interpreted as an ERA0 timestamp.
+ */
+ private static final Instant LATE_ERA0_REQUEST_TIME =
+ Timestamp64.fromString("d9ca9451.938a3771").toInstant(0);
+
+ // A tweaked version of the ERA0 response to represent an ERA 1 response.
+ //
+ // Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20
+ // Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41
+ // Reference Timestamp:
+ // 1db2d246.820a5000 / ERA0: 1915-10-16 21:08:22 UTC / ERA1: 2051-11-22 03:36:38 UTC
+ // Originate Timestamp:
+ // 1db2d251.938a3771 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ // Receive Timestamp:
+ // 1db2d251.94bd3fff / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ // Transmit Timestamp:
+ // 1db2d251.94bd4001 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ //
+ // Originate - Receive Timestamp: +0.004684958
+ // Originate - Transmit Timestamp: +0.004684958
+ private static final String EARLY_ERA_RESPONSE =
+ "240206ec"
+ + "00000165"
+ + "000000b2"
+ + "ddfd4729"
+ + "1db2d246820a5000"
+ + "1db2d251938a3771"
+ + "1db2d25194bd3fff"
+ + "1db2d25194bd4001";
+
+ /** This is the actual UTC time in the server if it is in ERA0 */
+ private static final Instant EARLY_ERA1_SERVER_TIME =
+ calculateIdealServerTime("1db2d251.94bd3fff", "1db2d251.94bd4001", 1);
+
+ /**
+ * This is the Unix epoch time matches the originate timestamp from {@link #EARLY_ERA_RESPONSE}
+ * when interpreted as an ERA1 timestamp.
+ */
+ private static final Instant EARLY_ERA1_REQUEST_TIME =
+ Timestamp64.fromString("1db2d251.938a3771").toInstant(1);
private SntpTestServer mServer;
private SntpClient mClient;
private Network mNetwork;
+ private Supplier<Instant> mSystemTimeSupplier;
+ private Random mRandom;
+ @SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
+ mServer = new SntpTestServer();
+
// A mock network has NETID_UNSET, which allows the test to run, with a loopback server,
// even w/o external networking.
mNetwork = mock(Network.class, CALLS_REAL_METHODS);
- mServer = new SntpTestServer();
- mClient = new SntpClient();
+ mRandom = mock(Random.class);
+
+ mSystemTimeSupplier = mock(Supplier.class);
+ // Returning zero means the "randomized" bottom bits of the clients transmit timestamp /
+ // server's originate timestamp will be zeros.
+ when(mRandom.nextInt()).thenReturn(0);
+ mClient = new SntpClient(mSystemTimeSupplier, mRandom);
}
+ /** Tests when the client and server are in ERA0. b/199481251. */
@Test
- public void testBasicWorkingSntpClientQuery() throws Exception {
- mServer.setServerReply(HexEncoding.decode(WORKING_VERSION4.toCharArray(), false));
+ public void testRequestTime_era0ClientEra0RServer() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false));
assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
assertEquals(1, mServer.numRequestsReceived());
assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient);
+ }
+
+ /** Tests when the client is behind the server and in the previous ERA. b/199481251. */
+ @Test
+ public void testRequestTime_era0ClientEra1Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient);
+
+ }
+
+ /** Tests when the client is ahead of the server and in the next ERA. b/199481251. */
+ @Test
+ public void testRequestTime_era1ClientEra0Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient);
+ }
+
+ /** Tests when the client and server are in ERA1. b/199481251. */
+ @Test
+ public void testRequestTime_era1ClientEra1Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient);
+ }
+
+ private static void checkRequestTimeCalcs(
+ Instant clientTime, Instant serverTime, SntpClient client) {
+ // The tests don't attempt to control the elapsed time tracking, which influences the
+ // round trip time (i.e. time spent in due to the network), but they control everything
+ // else, so assertions are allowed some slop and round trip time just has to be >= 0.
+ assertTrue("getRoundTripTime()=" + client.getRoundTripTime(),
+ client.getRoundTripTime() >= 0);
+
+ // Calculate the ideal offset if nothing took any time.
+ long expectedOffset = serverTime.toEpochMilli() - clientTime.toEpochMilli();
+ long allowedSlop = (client.getRoundTripTime() / 2) + 1; // +1 to allow for truncation loss.
+ assertNearlyEquals(expectedOffset, client.getClockOffset(), allowedSlop);
+ assertNearlyEquals(clientTime.toEpochMilli() + expectedOffset,
+ client.getNtpTime(), allowedSlop);
+ }
+
+ /**
+ * Unit tests for the low-level offset calculations. More targeted / easier to write than the
+ * end-to-end tests above that simulate the server. b/199481251.
+ */
+ @Test
+ public void testCalculateClockOffset() {
+ Instant era0Time1 = utcInstant(2021, 10, 5, 2, 2, 2, 2);
+ // Confirm what happens when the client and server are completely in sync.
+ checkCalculateClockOffset(era0Time1, era0Time1);
+
+ Instant era0Time2 = utcInstant(2021, 10, 6, 1, 1, 1, 1);
+ checkCalculateClockOffset(era0Time1, era0Time2);
+ checkCalculateClockOffset(era0Time2, era0Time1);
+
+ Instant era1Time1 = utcInstant(2061, 10, 5, 2, 2, 2, 2);
+ checkCalculateClockOffset(era1Time1, era1Time1);
+
+ Instant era1Time2 = utcInstant(2061, 10, 6, 1, 1, 1, 1);
+ checkCalculateClockOffset(era1Time1, era1Time2);
+ checkCalculateClockOffset(era1Time2, era1Time1);
+
+ // Cross-era calcs (requires they are still within 68 years of each other).
+ checkCalculateClockOffset(era0Time1, era1Time1);
+ checkCalculateClockOffset(era1Time1, era0Time1);
+ }
+
+ private void checkCalculateClockOffset(Instant clientTime, Instant serverTime) {
+ // The expected (ideal) offset is the difference between the client and server clocks. NTP
+ // assumes delays are symmetric, i.e. that the server time is between server
+ // receive/transmit time, client time is between request/response time, and send networking
+ // delay == receive networking delay.
+ Duration expectedOffset = Duration.between(clientTime, serverTime);
+
+ // Try simulating various round trip delays, including zero.
+ for (long totalElapsedTimeMillis : Arrays.asList(0, 20, 200, 2000, 20000)) {
+ // Simulate that a 10% of the elapsed time is due to time spent in the server, the rest
+ // is network / client processing time.
+ long simulatedServerElapsedTimeMillis = totalElapsedTimeMillis / 10;
+ long simulatedClientElapsedTimeMillis = totalElapsedTimeMillis;
+
+ // Create some symmetrical timestamps.
+ Timestamp64 clientRequestTimestamp = Timestamp64.fromInstant(
+ clientTime.minusMillis(simulatedClientElapsedTimeMillis / 2));
+ Timestamp64 clientResponseTimestamp = Timestamp64.fromInstant(
+ clientTime.plusMillis(simulatedClientElapsedTimeMillis / 2));
+ Timestamp64 serverReceiveTimestamp = Timestamp64.fromInstant(
+ serverTime.minusMillis(simulatedServerElapsedTimeMillis / 2));
+ Timestamp64 serverTransmitTimestamp = Timestamp64.fromInstant(
+ serverTime.plusMillis(simulatedServerElapsedTimeMillis / 2));
+
+ Duration actualOffset = SntpClient.calculateClockOffset(
+ clientRequestTimestamp, serverReceiveTimestamp,
+ serverTransmitTimestamp, clientResponseTimestamp);
+
+ // We allow up to 1ms variation because NTP types are lossy and the simulated elapsed
+ // time millis may not divide exactly.
+ int allowedSlopMillis = 1;
+ assertNearlyEquals(
+ expectedOffset.toMillis(), actualOffset.toMillis(), allowedSlopMillis);
+ }
+ }
+
+ private static Instant utcInstant(
+ int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) {
+ return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos)
+ .toInstant(ZoneOffset.UTC);
}
@Test
@@ -98,6 +298,8 @@
@Test
public void testTimeoutFailure() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
mServer.clearServerReply();
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
assertEquals(1, mServer.numRequestsReceived());
@@ -106,7 +308,9 @@
@Test
public void testIgnoreLeapNoSync() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
reply[0] |= (byte) 0xc0;
mServer.setServerReply(reply);
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
@@ -116,7 +320,9 @@
@Test
public void testAcceptOnlyServerAndBroadcastModes() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
for (int i = 0; i <= 7; i++) {
final String logMsg = "mode: " + i;
reply[0] &= (byte) 0xf8;
@@ -140,10 +346,12 @@
@Test
public void testAcceptableStrataOnly() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
final int STRATUM_MIN = 1;
final int STRATUM_MAX = 15;
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
for (int i = 0; i < 256; i++) {
final String logMsg = "stratum: " + i;
reply[1] = (byte) i;
@@ -162,7 +370,9 @@
@Test
public void testZeroTransmitTime() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
Arrays.fill(reply, TRANSMIT_TIME_OFFSET, TRANSMIT_TIME_OFFSET + 8, (byte) 0x00);
mServer.setServerReply(reply);
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
@@ -170,6 +380,19 @@
assertEquals(1, mServer.numRepliesSent());
}
+ @Test
+ public void testNonMatchingOriginateTime() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
+ mServer.setServerReply(reply);
+ mServer.setGenerateValidOriginateTimestamp(false);
+
+ assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+ }
+
private static class SntpTestServer {
private final Object mLock = new Object();
@@ -177,6 +400,7 @@
private final InetAddress mAddress;
private final int mPort;
private byte[] mReply;
+ private boolean mGenerateValidOriginateTimestamp = true;
private int mRcvd;
private int mSent;
private Thread mListeningThread;
@@ -201,10 +425,16 @@
synchronized (mLock) {
mRcvd++;
if (mReply == null) { continue; }
- // Copy transmit timestamp into originate timestamp.
- // TODO: bounds checking.
- System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET,
- mReply, ORIGINATE_TIME_OFFSET, 8);
+ if (mGenerateValidOriginateTimestamp) {
+ // Copy the transmit timestamp into originate timestamp: This is
+ // validated by well-behaved clients.
+ System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET,
+ mReply, ORIGINATE_TIME_OFFSET, 8);
+ } else {
+ // Fill it with junk instead.
+ Arrays.fill(mReply, ORIGINATE_TIME_OFFSET,
+ ORIGINATE_TIME_OFFSET + 8, (byte) 0xFF);
+ }
ntpMsg.setData(mReply);
ntpMsg.setLength(mReply.length);
try {
@@ -245,9 +475,38 @@
}
}
+ /**
+ * Controls the test server's behavior of copying the client's transmit timestamp into the
+ * response's originate timestamp (which is required of a real server).
+ */
+ public void setGenerateValidOriginateTimestamp(boolean enabled) {
+ synchronized (mLock) {
+ mGenerateValidOriginateTimestamp = enabled;
+ }
+ }
+
public InetAddress getAddress() { return mAddress; }
public int getPort() { return mPort; }
public int numRequestsReceived() { synchronized (mLock) { return mRcvd; } }
public int numRepliesSent() { synchronized (mLock) { return mSent; } }
}
+
+ /**
+ * Generates the "real" server time assuming it is exactly between the receive and transmit
+ * timestamp and in the NTP era specified.
+ */
+ private static Instant calculateIdealServerTime(String receiveTimestampString,
+ String transmitTimestampString, int era) {
+ Timestamp64 receiveTimestamp = Timestamp64.fromString(receiveTimestampString);
+ Timestamp64 transmitTimestamp = Timestamp64.fromString(transmitTimestampString);
+ Duration serverProcessingTime =
+ Duration64.between(receiveTimestamp, transmitTimestamp).toDuration();
+ return receiveTimestamp.toInstant(era)
+ .plusMillis(serverProcessingTime.dividedBy(2).toMillis());
+ }
+
+ private static void assertNearlyEquals(long expected, long actual, long allowedSlop) {
+ assertTrue("expected=" + expected + ", actual=" + actual + ", allowedSlop=" + allowedSlop,
+ actual >= expected - allowedSlop && actual <= expected + allowedSlop);
+ }
}
diff --git a/core/tests/coretests/src/android/net/sntp/Duration64Test.java b/core/tests/coretests/src/android/net/sntp/Duration64Test.java
new file mode 100644
index 0000000..60b69f6
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/Duration64Test.java
@@ -0,0 +1,268 @@
+/*
+ * 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 android.net.sntp;
+
+import static android.net.sntp.Timestamp64.NANOS_PER_SECOND;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+public class Duration64Test {
+
+ @Test
+ public void testBetween_rangeChecks() {
+ long maxDuration64Seconds = Timestamp64.MAX_SECONDS_IN_ERA / 2;
+
+ Timestamp64 zeroNoFrac = Timestamp64.fromComponents(0, 0);
+ assertEquals(Duration64.ZERO, Duration64.between(zeroNoFrac, zeroNoFrac));
+
+ {
+ Timestamp64 ceilNoFrac = Timestamp64.fromComponents(maxDuration64Seconds, 0);
+ assertEquals(Duration64.ZERO, Duration64.between(ceilNoFrac, ceilNoFrac));
+
+ long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(zeroNoFrac, ceilNoFrac).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(ceilNoFrac, zeroNoFrac).toDuration());
+ }
+
+ {
+ // This value is the largest fraction of a second representable. It is 1-(1/2^32)), and
+ // so numerically larger than 999_999_999 nanos.
+ int fractionBits = 0xFFFF_FFFF;
+ Timestamp64 ceilWithFrac = Timestamp64
+ .fromComponents(maxDuration64Seconds, fractionBits);
+ assertEquals(Duration64.ZERO, Duration64.between(ceilWithFrac, ceilWithFrac));
+
+ long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND + 999_999_999;
+ assertEquals(
+ Duration.ofNanos(expectedNanos),
+ Duration64.between(zeroNoFrac, ceilWithFrac).toDuration());
+ // The -1 nanos demonstrates asymmetry due to the way Duration64 has different
+ // precision / range of sub-second fractions.
+ assertEquals(
+ Duration.ofNanos(-expectedNanos - 1),
+ Duration64.between(ceilWithFrac, zeroNoFrac).toDuration());
+ }
+ }
+
+ @Test
+ public void testBetween_smallSecondsOnly() {
+ long expectedNanos = 5L * NANOS_PER_SECOND;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(Timestamp64.fromComponents(5, 0),
+ Timestamp64.fromComponents(10, 0))
+ .toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(Timestamp64.fromComponents(10, 0),
+ Timestamp64.fromComponents(5, 0))
+ .toDuration());
+ }
+
+ @Test
+ public void testBetween_smallSecondsAndFraction() {
+ // Choose a nanos values we know can be represented exactly with fixed point binary (1/2
+ // second, 1/4 second, etc.).
+ {
+ long expectedNanos = 5L * NANOS_PER_SECOND + 500_000_000L;
+ int fractionHalfSecond = 0x8000_0000;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(5, 0),
+ Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(10, fractionHalfSecond),
+ Timestamp64.fromComponents(5, 0)).toDuration());
+ }
+
+ {
+ long expectedNanos = 5L * NANOS_PER_SECOND + 250_000_000L;
+ int fractionHalfSecond = 0x8000_0000;
+ int fractionQuarterSecond = 0x4000_0000;
+
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(5, fractionQuarterSecond),
+ Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(10, fractionHalfSecond),
+ Timestamp64.fromComponents(5, fractionQuarterSecond)).toDuration());
+ }
+
+ }
+
+ @Test
+ public void testBetween_sameEra0() {
+ int arbitraryEra0Year = 2021;
+ Instant one = utcInstant(arbitraryEra0Year, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryEra0Year + 1, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 0);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ @Test
+ public void testBetween_sameEra1() {
+ int arbitraryEra1Year = 2037;
+ Instant one = utcInstant(arbitraryEra1Year, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 1);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryEra1Year + 1, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ /**
+ * Tests that two timestamps can originate from times in different eras, and the works
+ * calculation still works providing the two times aren't more than 68 years apart (half of the
+ * 136 years representable using an unsigned 32-bit seconds representation).
+ */
+ @Test
+ public void testBetween_adjacentEras() {
+ int yearsSeparation = 68;
+
+ // This year just needs to be < 68 years before the end of NTP timestamp era 0.
+ int arbitraryYearInEra0 = 2021;
+
+ Instant one = utcInstant(arbitraryYearInEra0, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryYearInEra0 + yearsSeparation, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ /**
+ * This test confirms that duration calculations fail in the expected fashion if two
+ * Timestamp64s are more than 2^31 seconds apart.
+ *
+ * <p>The types / math specified by NTP for timestamps deliberately takes place in 64-bit signed
+ * arithmetic for the bits used to represent timestamps (32-bit unsigned integer seconds,
+ * 32-bits fixed point for fraction of seconds). Timestamps can therefore represent ~136 years
+ * of seconds.
+ * When subtracting one timestamp from another, we end up with a signed 32-bit seconds value.
+ * This means the max duration representable is ~68 years before numbers will over or underflow.
+ * i.e. the client and server are in the same or adjacent NTP eras and the difference in their
+ * clocks isn't more than ~68 years. >= ~68 years and things break down.
+ */
+ @Test
+ public void testBetween_tooFarApart() {
+ int tooManyYearsSeparation = 68 + 1;
+
+ Instant one = utcInstant(2021, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+ Instant two = utcInstant(2021 + tooManyYearsSeparation, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64OverflowBehavior(one, two);
+ checkDuration64OverflowBehavior(two, one);
+ }
+
+ private static void checkDuration64Behavior(Instant one, Instant two) {
+ // This is the answer if we perform the arithmetic in a lossless fashion.
+ Duration expectedDuration = Duration.between(one, two);
+ Duration64 expectedDuration64 = Duration64.fromDuration(expectedDuration);
+
+ // Sub-second precision is limited in Timestamp64, so we can lose 1ms.
+ assertEqualsOrSlightlyLessThan(
+ expectedDuration.toMillis(), expectedDuration64.toDuration().toMillis());
+
+ Timestamp64 one64 = Timestamp64.fromInstant(one);
+ Timestamp64 two64 = Timestamp64.fromInstant(two);
+
+ // This is the answer if we perform the arithmetic in a lossy fashion.
+ Duration64 actualDuration64 = Duration64.between(one64, two64);
+ assertEquals(expectedDuration64.getSeconds(), actualDuration64.getSeconds());
+ assertEqualsOrSlightlyLessThan(expectedDuration64.getNanos(), actualDuration64.getNanos());
+ }
+
+ private static void checkDuration64OverflowBehavior(Instant one, Instant two) {
+ // This is the answer if we perform the arithmetic in a lossless fashion.
+ Duration trueDuration = Duration.between(one, two);
+
+ // Confirm the maths is expected to overflow / underflow.
+ assertTrue(trueDuration.getSeconds() > Integer.MAX_VALUE / 2
+ || trueDuration.getSeconds() < Integer.MIN_VALUE / 2);
+
+ // Now perform the arithmetic as specified for NTP: do subtraction using the 64-bit
+ // timestamp.
+ Timestamp64 one64 = Timestamp64.fromInstant(one);
+ Timestamp64 two64 = Timestamp64.fromInstant(two);
+
+ Duration64 actualDuration64 = Duration64.between(one64, two64);
+ assertNotEquals(trueDuration.getSeconds(), actualDuration64.getSeconds());
+ }
+
+ /**
+ * Asserts the instant provided is in the specified NTP timestamp era. Used to confirm /
+ * document values picked for tests have the properties needed.
+ */
+ private static void assertNtpEraOfInstant(Instant one, int ntpEra) {
+ long expectedSeconds = one.getEpochSecond();
+
+ // The conversion to Timestamp64 is lossy (it loses the era). We then supply the expected
+ // era. If the era was correct, we will end up with the value we started with (modulo nano
+ // precision loss). If the era is wrong, we won't.
+ Instant roundtrippedInstant = Timestamp64.fromInstant(one).toInstant(ntpEra);
+
+ long actualSeconds = roundtrippedInstant.getEpochSecond();
+ assertEquals(expectedSeconds, actualSeconds);
+ }
+
+ /**
+ * Used to account for the fact that NTP types used 32-bit fixed point storage, so cannot store
+ * all values precisely. The value we get out will always be the value we put in, or one that is
+ * one unit smaller (due to truncation).
+ */
+ private static void assertEqualsOrSlightlyLessThan(long expected, long actual) {
+ assertTrue("expected=" + expected + ", actual=" + actual,
+ expected == actual || expected == actual - 1);
+ }
+
+ private static Instant utcInstant(
+ int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) {
+ return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos)
+ .toInstant(ZoneOffset.UTC);
+ }
+}
diff --git a/core/tests/coretests/src/android/net/sntp/PredictableRandom.java b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java
new file mode 100644
index 0000000..bb2922b
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.net.sntp;
+
+import java.util.Random;
+
+class PredictableRandom extends Random {
+ private int[] mIntSequence = new int[] { 1 };
+ private int mIntPos = 0;
+
+ public void setIntSequence(int[] intSequence) {
+ this.mIntSequence = intSequence;
+ }
+
+ @Override
+ public int nextInt() {
+ int value = mIntSequence[mIntPos++];
+ mIntPos %= mIntSequence.length;
+ return value;
+ }
+}
diff --git a/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java
new file mode 100644
index 0000000..1b1c500c
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java
@@ -0,0 +1,316 @@
+/*
+ * 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 android.net.sntp;
+
+import static android.net.sntp.Timestamp64.NANOS_PER_SECOND;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Instant;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class Timestamp64Test {
+
+ @Test
+ public void testFromComponents() {
+ long minNtpEraSeconds = 0;
+ long maxNtpEraSeconds = 0xFFFFFFFFL;
+
+ expectIllegalArgumentException(() -> Timestamp64.fromComponents(minNtpEraSeconds - 1, 0));
+ expectIllegalArgumentException(() -> Timestamp64.fromComponents(maxNtpEraSeconds + 1, 0));
+
+ assertComponentCreation(minNtpEraSeconds, 0);
+ assertComponentCreation(maxNtpEraSeconds, 0);
+ assertComponentCreation(maxNtpEraSeconds, Integer.MIN_VALUE);
+ assertComponentCreation(maxNtpEraSeconds, Integer.MAX_VALUE);
+ }
+
+ private static void assertComponentCreation(long ntpEraSeconds, int fractionBits) {
+ Timestamp64 value = Timestamp64.fromComponents(ntpEraSeconds, fractionBits);
+ assertEquals(ntpEraSeconds, value.getEraSeconds());
+ assertEquals(fractionBits, value.getFractionBits());
+ }
+
+ @Test
+ public void testEqualsAndHashcode() {
+ assertEqualsAndHashcode(0, 0);
+ assertEqualsAndHashcode(1, 0);
+ assertEqualsAndHashcode(0, 1);
+ }
+
+ private static void assertEqualsAndHashcode(int eraSeconds, int fractionBits) {
+ Timestamp64 one = Timestamp64.fromComponents(eraSeconds, fractionBits);
+ Timestamp64 two = Timestamp64.fromComponents(eraSeconds, fractionBits);
+ assertEquals(one, two);
+ assertEquals(one.hashCode(), two.hashCode());
+ }
+
+ @Test
+ public void testStringForm() {
+ expectIllegalArgumentException(() -> Timestamp64.fromString(""));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("."));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1234567812345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678?12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678..12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("123456.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1234567.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.12"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.123456"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1234567"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("X2345678.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.X2345678"));
+
+ assertStringCreation("00000000.00000000", 0, 0);
+ assertStringCreation("00000001.00000001", 1, 1);
+ assertStringCreation("ffffffff.ffffffff", 0xFFFFFFFFL, 0xFFFFFFFF);
+ }
+
+ private static void assertStringCreation(
+ String string, long expectedSeconds, int expectedFractionBits) {
+ Timestamp64 timestamp64 = Timestamp64.fromString(string);
+ assertEquals(string, timestamp64.toString());
+ assertEquals(expectedSeconds, timestamp64.getEraSeconds());
+ assertEquals(expectedFractionBits, timestamp64.getFractionBits());
+ }
+
+ @Test
+ public void testStringForm_lenientHexCasing() {
+ Timestamp64 mixedCaseValue = Timestamp64.fromString("AaBbCcDd.EeFf1234");
+ assertEquals(0xAABBCCDDL, mixedCaseValue.getEraSeconds());
+ assertEquals(0xEEFF1234, mixedCaseValue.getFractionBits());
+ }
+
+ @Test
+ public void testFromInstant_secondsHandling() {
+ final int era0 = 0;
+ final int eraNeg1 = -1;
+ final int eraNeg2 = -2;
+ final int era1 = 1;
+
+ assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970, 0, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA, 0, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA, 0, era1);
+
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - 1, Timestamp64.MAX_SECONDS_IN_ERA, -1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA - 1,
+ Timestamp64.MAX_SECONDS_IN_ERA, eraNeg2);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA - 1,
+ Timestamp64.MAX_SECONDS_IN_ERA, era0);
+
+ assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970 + 1, 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA + 1, 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA + 1, 1, era1);
+
+ assertInstantCreationOnlySeconds(0, Timestamp64.OFFSET_1900_TO_1970, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, era1);
+
+ assertInstantCreationOnlySeconds(1, Timestamp64.OFFSET_1900_TO_1970 + 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, era1);
+
+ assertInstantCreationOnlySeconds(-1, Timestamp64.OFFSET_1900_TO_1970 - 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, era1);
+ }
+
+ private static void assertInstantCreationOnlySeconds(
+ long epochSeconds, long expectedNtpEraSeconds, int ntpEra) {
+ int nanosOfSecond = 0;
+ Instant instant = Instant.ofEpochSecond(epochSeconds, nanosOfSecond);
+ Timestamp64 timestamp = Timestamp64.fromInstant(instant);
+ assertEquals(expectedNtpEraSeconds, timestamp.getEraSeconds());
+
+ int expectedFractionBits = 0;
+ assertEquals(expectedFractionBits, timestamp.getFractionBits());
+
+ // Confirm the Instant can be round-tripped if we know the era. Also assumes the nanos can
+ // be stored precisely; 0 can be.
+ Instant roundTrip = timestamp.toInstant(ntpEra);
+ assertEquals(instant, roundTrip);
+ }
+
+ @Test
+ public void testFromInstant_fractionHandling() {
+ // Try some values we know can be represented exactly.
+ assertInstantCreationOnlyFractionExact(0x0, 0);
+ assertInstantCreationOnlyFractionExact(0x80000000, 500_000_000L);
+ assertInstantCreationOnlyFractionExact(0x40000000, 250_000_000L);
+
+ // Test the limits of precision.
+ assertInstantCreationOnlyFractionExact(0x00000006, 1L);
+ assertInstantCreationOnlyFractionExact(0x00000005, 1L);
+ assertInstantCreationOnlyFractionExact(0x00000004, 0L);
+ assertInstantCreationOnlyFractionExact(0x00000002, 0L);
+ assertInstantCreationOnlyFractionExact(0x00000001, 0L);
+
+ // Confirm nanosecond storage / precision is within 1ns.
+ final boolean exhaustive = false;
+ for (int i = 0; i < NANOS_PER_SECOND; i++) {
+ Instant instant = Instant.ofEpochSecond(0, i);
+ Instant roundTripped = Timestamp64.fromInstant(instant).toInstant(0);
+ assertNanosWithTruncationAllowed(i, roundTripped);
+ if (!exhaustive) {
+ i += 999_999;
+ }
+ }
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ private static void assertInstantCreationOnlyFractionExact(
+ int fractionBits, long expectedNanos) {
+ Timestamp64 timestamp64 = Timestamp64.fromComponents(0, fractionBits);
+
+ final int ntpEra = 0;
+ Instant instant = timestamp64.toInstant(ntpEra);
+
+ assertEquals(expectedNanos, instant.getNano());
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ private static void assertNanosWithTruncationAllowed(long expectedNanos, Instant instant) {
+ // Allow for < 1ns difference due to truncation.
+ long actualNanos = instant.getNano();
+ assertTrue("expectedNanos=" + expectedNanos + ", actualNanos=" + actualNanos,
+ actualNanos == expectedNanos || actualNanos == expectedNanos - 1);
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ @Test
+ public void testMillisRandomizationConstant() {
+ // Mathematically, we can say that to represent 1000 different values, we need 10 binary
+ // digits (2^10 = 1024). The same is true whether we're dealing with integers or fractions.
+ // Unfortunately, for fractions those 1024 values do not correspond to discrete decimal
+ // values. Discrete millisecond values as fractions (e.g. 0.001 - 0.999) cannot be
+ // represented exactly except where the value can also be represented as some combination of
+ // powers of -2. When we convert back and forth, we truncate, so millisecond decimal
+ // fraction N represented as a binary fraction will always be equal to or lower than N. If
+ // we are truncating correctly it will never be as low as (N-0.001). N -> [N-0.001, N].
+
+ // We need to keep 10 bits to hold millis (inaccurately, since there are numbers that
+ // cannot be represented exactly), leaving us able to randomize the remaining 22 bits of the
+ // fraction part without significantly affecting the number represented.
+ assertEquals(22, Timestamp64.SUB_MILLIS_BITS_TO_RANDOMIZE);
+
+ // Brute force proof that randomization logic will keep the timestamp within the range
+ // [N-0.001, N] where x is in milliseconds.
+ int smallFractionRandomizedLow = 0;
+ int smallFractionRandomizedHigh = 0b00000000_00111111_11111111_11111111;
+ int largeFractionRandomizedLow = 0b11111111_11000000_00000000_00000000;
+ int largeFractionRandomizedHigh = 0b11111111_11111111_11111111_11111111;
+
+ long smallLowNanos = Timestamp64.fromComponents(
+ 0, smallFractionRandomizedLow).toInstant(0).getNano();
+ long smallHighNanos = Timestamp64.fromComponents(
+ 0, smallFractionRandomizedHigh).toInstant(0).getNano();
+ long smallDelta = smallHighNanos - smallLowNanos;
+ long millisInNanos = 1_000_000_000 / 1_000;
+ assertTrue(smallDelta >= 0 && smallDelta < millisInNanos);
+
+ long largeLowNanos = Timestamp64.fromComponents(
+ 0, largeFractionRandomizedLow).toInstant(0).getNano();
+ long largeHighNanos = Timestamp64.fromComponents(
+ 0, largeFractionRandomizedHigh).toInstant(0).getNano();
+ long largeDelta = largeHighNanos - largeLowNanos;
+ assertTrue(largeDelta >= 0 && largeDelta < millisInNanos);
+
+ PredictableRandom random = new PredictableRandom();
+ random.setIntSequence(new int[] { 0xFFFF_FFFF });
+ Timestamp64 zero = Timestamp64.fromComponents(0, 0);
+ Timestamp64 zeroWithFractionRandomized = zero.randomizeSubMillis(random);
+ assertEquals(zero.getEraSeconds(), zeroWithFractionRandomized.getEraSeconds());
+ assertEquals(smallFractionRandomizedHigh, zeroWithFractionRandomized.getFractionBits());
+ }
+
+ @Test
+ public void testRandomizeLowestBits() {
+ Random random = new Random(1);
+ {
+ int fractionBits = 0;
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, -1));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, 0));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE + 1));
+ }
+
+ // Check the behavior looks correct from a probabilistic point of view.
+ for (int input : new int[] { 0, 0xFFFFFFFF }) {
+ for (int bitCount = 1; bitCount < Integer.SIZE; bitCount++) {
+ int upperBitMask = 0xFFFFFFFF << bitCount;
+ int expectedUpperBits = input & upperBitMask;
+
+ Set<Integer> values = new HashSet<>();
+ values.add(input);
+
+ int trials = 100;
+ for (int i = 0; i < trials; i++) {
+ int outputFractionBits =
+ Timestamp64.randomizeLowestBits(random, input, bitCount);
+
+ // Record the output value for later analysis.
+ values.add(outputFractionBits);
+
+ // Check upper bits did not change.
+ assertEquals(expectedUpperBits, outputFractionBits & upperBitMask);
+ }
+
+ // It's possible to be more rigorous here, perhaps with a histogram. As bitCount
+ // rises, values.size() quickly trend towards the value of trials + 1. For now, this
+ // mostly just guards against a no-op implementation.
+ assertTrue(bitCount + ":" + values.size(), values.size() > 1);
+ }
+ }
+ }
+
+ private static void expectIllegalArgumentException(Runnable r) {
+ try {
+ r.run();
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
index c50c818..e2c40d8 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
@@ -28,6 +28,7 @@
import com.android.internal.content.om.OverlayConfig.PackageProvider;
import com.android.internal.content.om.OverlayScanner;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
+import com.android.internal.util.function.TriConsumer;
import org.junit.Assert;
import org.junit.rules.TestRule;
@@ -39,7 +40,6 @@
import java.io.File;
import java.io.IOException;
import java.util.Map;
-import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
@@ -73,7 +73,7 @@
final File canonicalPath = new File(path.getCanonicalPath());
mOverlayStubResults.put(canonicalPath, new ParsedOverlayInfo(
packageName, targetPackage, targetSdkVersion, isStatic, priority,
- canonicalPath));
+ canonicalPath, null));
} catch (IOException e) {
Assert.fail("Failed to add overlay " + e);
}
@@ -135,8 +135,8 @@
mIteration = Iteration.SYSTEM_SERVER;
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final BiConsumer<ParsingPackageRead, Boolean> f =
- (BiConsumer<ParsingPackageRead, Boolean>) args[0];
+ final TriConsumer<ParsingPackageRead, Boolean, File> f =
+ (TriConsumer<ParsingPackageRead, Boolean, File>) args[0];
for (Map.Entry<File, ParsedOverlayInfo> overlay :
mOverlayStubResults.entrySet()) {
final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
@@ -147,7 +147,8 @@
when(a.isOverlayIsStatic()).thenReturn(info.isStatic);
when(a.getOverlayPriority()).thenReturn(info.priority);
when(a.getBaseApkPath()).thenReturn(info.path.getPath());
- f.accept(a, !info.path.getPath().contains("data/overlay"));
+ f.accept(a, !info.path.getPath().contains("data/overlay"),
+ /*preInstalledApexPath=*/null);
}
return null;
}).when(mPkgProvider).forEachPackage(any());
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 5c84794..d361da9 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -33,6 +33,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class BluetoothPowerCalculatorTest {
@@ -105,10 +107,10 @@
final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0,
reportedEnergyUc);
- info.setUidTraffic(new UidTraffic[]{
- new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
- new UidTraffic(APP_UID, 3000, 4000)
- });
+ info.setUidTraffic(new ArrayList<UidTraffic>(){{
+ add(new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000));
+ add(new UidTraffic(APP_UID, 3000, 4000));
+ }});
mStatsRule.getBatteryStats().updateBluetoothStateLocked(info,
consumedEnergyUc, 1000, 1000);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c068963..ed8cdb9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5203,21 +5203,6 @@
}
}
- /**
- * @hide
- * Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
- * so that AudioService can send volume change events to the A2DP device, rather than handling
- * them.
- */
- public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
- final IAudioService service = getService();
- try {
- service.avrcpSupportsAbsoluteVolume(address, support);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
* {@hide}
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7191280..dd44fdf 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -171,8 +171,6 @@
int getEncodedSurroundMode(int targetSdkVersion);
- oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
-
void setSpeakerphoneOn(IBinder cb, boolean on);
boolean isSpeakerphoneOn();
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 49477b9..374cc75 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -182,10 +182,15 @@
public String mName;
public int mValue;
public boolean mDefault;
+ public boolean mInternal;
public Feature(String name, int value, boolean def) {
+ this(name, value, def, false /* internal */);
+ }
+ public Feature(String name, int value, boolean def, boolean internal) {
mName = name;
mValue = value;
mDefault = def;
+ mInternal = internal;
}
}
@@ -579,6 +584,11 @@
public static final String FEATURE_LowLatency = "low-latency";
/**
+ * Do not include in REGULAR_CODECS list in MediaCodecList.
+ */
+ private static final String FEATURE_SpecialCodec = "special-codec";
+
+ /**
* <b>video encoder only</b>: codec supports quantization parameter bounds.
* @see MediaFormat#KEY_VIDEO_QP_MAX
* @see MediaFormat#KEY_VIDEO_QP_MIN
@@ -616,6 +626,8 @@
new Feature(FEATURE_MultipleFrames, (1 << 5), false),
new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
new Feature(FEATURE_LowLatency, (1 << 7), true),
+ // feature to exclude codec from REGULAR codec list
+ new Feature(FEATURE_SpecialCodec, (1 << 30), false, true),
};
private static final Feature[] encoderFeatures = {
@@ -623,6 +635,8 @@
new Feature(FEATURE_MultipleFrames, (1 << 1), false),
new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
new Feature(FEATURE_QpBounds, (1 << 3), false),
+ // feature to exclude codec from REGULAR codec list
+ new Feature(FEATURE_SpecialCodec, (1 << 30), false, true),
};
/** @hide */
@@ -630,7 +644,9 @@
Feature[] features = getValidFeatures();
String[] res = new String[features.length];
for (int i = 0; i < res.length; i++) {
- res[i] = features[i].mName;
+ if (!features[i].mInternal) {
+ res[i] = features[i].mName;
+ }
}
return res;
}
@@ -778,6 +794,10 @@
// check feature support
for (Feature feat: getValidFeatures()) {
+ if (feat.mInternal) {
+ continue;
+ }
+
Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName);
if (yesNo == null) {
continue;
@@ -1091,7 +1111,9 @@
mFlagsRequired |= feat.mValue;
}
mFlagsSupported |= feat.mValue;
- mDefaultFormat.setInteger(key, 1);
+ if (!feat.mInternal) {
+ mDefaultFormat.setInteger(key, 1);
+ }
// TODO restrict features by mFlagsVerified once all codecs reliably verify them
}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index bc73f6a..c775b6f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -183,8 +183,8 @@
"libmedia",
"libnativehelper",
"libutils",
- "tv_tuner_aidl_interface-ndk_platform",
- "tv_tuner_resource_manager_aidl_interface-ndk_platform",
+ "tv_tuner_aidl_interface-ndk",
+ "tv_tuner_resource_manager_aidl_interface-ndk",
],
static_libs: [
diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS
index c633113..2736870 100644
--- a/packages/PackageInstaller/OWNERS
+++ b/packages/PackageInstaller/OWNERS
@@ -1,7 +1,5 @@
svetoslavganov@google.com
-toddke@google.com
-patb@google.com
-suprabh@google.com
+include /PACKAGE_MANAGER_OWNERS
# For automotive related changes
rogerxue@google.com
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS
index a0e28ba..5b2e1e3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/OWNERS
@@ -1,5 +1,6 @@
# Default reviewers for this and subdirectories.
takaoka@google.com
yukawa@google.com
+wilsonwu@google.com
# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS
index 6c61d4b9..5ade971 100644
--- a/packages/SettingsProvider/OWNERS
+++ b/packages/SettingsProvider/OWNERS
@@ -2,6 +2,4 @@
hackbod@google.com
narayan@google.com
svetoslavganov@google.com
-schfan@google.com
-toddke@google.com
-patb@google.com
+include /PACKAGE_MANAGER_OWNERS
diff --git a/services/core/java/android/content/pm/OWNERS b/services/core/java/android/content/pm/OWNERS
index 5eed0b5..3993140 100644
--- a/services/core/java/android/content/pm/OWNERS
+++ b/services/core/java/android/content/pm/OWNERS
@@ -1 +1 @@
-include /core/java/android/content/pm/OWNERS
\ No newline at end of file
+include /PACKAGE_MANAGER_OWNERS
\ No newline at end of file
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 1e608f5..0146aa8 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -81,8 +81,6 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
@@ -1435,11 +1433,7 @@
*/
public static final class HealthServiceWrapper {
private static final String TAG = "HealthServiceWrapper";
- public static final String INSTANCE_HEALTHD = "backup";
public static final String INSTANCE_VENDOR = "default";
- // All interesting instances, sorted by priority high -> low.
- private static final List<String> sAllInstances =
- Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
private final IServiceNotification mNotification = new Notification();
private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder");
@@ -1471,8 +1465,8 @@
}
/**
- * Start monitoring registration of new IHealth services. Only instances that are in
- * {@code sAllInstances} and in device / framework manifest are used. This function should
+ * 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
@@ -1481,7 +1475,7 @@
* @throws RemoteException transaction error when talking to IServiceManager
* @throws NoSuchElementException if one of the following cases:
* - No service manager;
- * - none of {@code sAllInstances} are in manifests (i.e. not
+ * - {@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
@@ -1499,26 +1493,23 @@
// Initialize mLastService and call callback for the first time (in init thread)
IHealth newService = null;
- for (String name : sAllInstances) {
- traceBegin("HealthInitGetService_" + name);
- try {
- newService = healthSupplier.get(name);
- } catch (NoSuchElementException ex) {
- /* ignored, handled below */
- } finally {
- traceEnd();
- }
- if (newService != null) {
- mInstanceName = name;
- mLastService.set(newService);
- break;
- }
+ 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(
- "No IHealth service instance among %s is available. Perhaps no permission?",
- sAllInstances.toString()));
+ "IHealth service instance %s isn't available. Perhaps no permission?",
+ INSTANCE_VENDOR));
}
if (callback != null) {
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 95dc667..b641377 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -16,6 +16,9 @@
# ServiceWatcher
per-file ServiceWatcher.java = sooniln@google.com
+# Health
+per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OWNERS
+
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Battery* = file:/BATTERY_STATS_OWNERS
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c11c4de..43bd9e7 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1029,7 +1029,6 @@
return;
}
- int phoneId = getPhoneIdFromSubId(subId);
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
@@ -1052,21 +1051,24 @@
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (DBG) {
+ log("invalid subscription id, use default id");
+ }
r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
} else {//APP specify subID
r.subId = subId;
}
- r.phoneId = phoneId;
+ r.phoneId = getPhoneIdFromSubId(r.subId);
r.eventList = events;
if (DBG) {
- log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+ log("listen: Register r=" + r + " r.subId=" + r.subId + " r.phoneId=" + r.phoneId);
}
- if (notifyNow && validatePhoneId(phoneId)) {
+ if (notifyNow && validatePhoneId(r.phoneId)) {
if (events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)){
try {
- if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
- ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+ if (VDBG) log("listen: call onSSC state=" + mServiceState[r.phoneId]);
+ ServiceState rawSs = new ServiceState(mServiceState[r.phoneId]);
if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onServiceStateChanged(rawSs);
} else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
@@ -1082,8 +1084,8 @@
}
if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) {
try {
- if (mSignalStrength[phoneId] != null) {
- int gsmSignalStrength = mSignalStrength[phoneId]
+ if (mSignalStrength[r.phoneId] != null) {
+ int gsmSignalStrength = mSignalStrength[r.phoneId]
.getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
@@ -1096,7 +1098,7 @@
TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
try {
r.callback.onMessageWaitingIndicatorChanged(
- mMessageWaiting[phoneId]);
+ mMessageWaiting[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1105,7 +1107,7 @@
TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
try {
r.callback.onCallForwardingIndicatorChanged(
- mCallForwarding[phoneId]);
+ mCallForwarding[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1113,11 +1115,11 @@
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) {
try {
- if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
+ if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[r.phoneId]);
if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
// null will be translated to empty CellLocation object in client.
- r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
+ r.callback.onCellLocationChanged(mCellIdentity[r.phoneId]);
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1125,38 +1127,38 @@
}
if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)) {
try {
- r.callback.onLegacyCallStateChanged(mCallState[phoneId],
- getCallIncomingNumber(r, phoneId));
+ r.callback.onLegacyCallStateChanged(mCallState[r.phoneId],
+ getCallIncomingNumber(r, r.phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) {
try {
- r.callback.onCallStateChanged(mCallState[phoneId]);
+ r.callback.onCallStateChanged(mCallState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
- mDataConnectionNetworkType[phoneId]);
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[r.phoneId],
+ mDataConnectionNetworkType[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)) {
try {
- r.callback.onDataActivity(mDataActivity[phoneId]);
+ r.callback.onDataActivity(mDataActivity[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
try {
- if (mSignalStrength[phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ if (mSignalStrength[r.phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]);
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1166,8 +1168,8 @@
TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
updateReportSignalStrengthDecision(r.subId);
try {
- if (mSignalStrength[phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ if (mSignalStrength[r.phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]);
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1176,11 +1178,13 @@
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) {
try {
- if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
- + mCellInfo.get(phoneId));
+ if (DBG_LOC) {
+ log("listen: mCellInfo[" + r.phoneId + "] = "
+ + mCellInfo.get(r.phoneId));
+ }
if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ r.callback.onCellInfoChanged(mCellInfo.get(r.phoneId));
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1188,22 +1192,22 @@
}
if (events.contains(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)) {
try {
- r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
+ r.callback.onPreciseCallStateChanged(mPreciseCallState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
try {
- r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
- mCallPreciseDisconnectCause[phoneId]);
+ r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[r.phoneId],
+ mCallPreciseDisconnectCause[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
try {
- r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+ r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(r.phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1212,7 +1216,7 @@
TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
try {
for (PreciseDataConnectionState pdcs
- : mPreciseDataConnectionStates.get(phoneId).values()) {
+ : mPreciseDataConnectionStates.get(r.phoneId).values()) {
r.callback.onPreciseDataConnectionStateChanged(pdcs);
}
} catch (RemoteException ex) {
@@ -1229,29 +1233,29 @@
if (events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
try {
r.callback.onVoiceActivationStateChanged(
- mVoiceActivationState[phoneId]);
+ mVoiceActivationState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
try {
- r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+ r.callback.onDataActivationStateChanged(mDataActivationState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
try {
- r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+ r.callback.onUserMobileDataStateChanged(mUserMobileDataState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) {
try {
- if (mTelephonyDisplayInfos[phoneId] != null) {
- r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
+ if (mTelephonyDisplayInfos[r.phoneId] != null) {
+ r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[r.phoneId]);
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1288,20 +1292,20 @@
}
if (events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)) {
try {
- r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
+ r.callback.onSrvccStateChanged(mSrvccState[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) {
try {
- r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+ r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED)) {
- BarringInfo barringInfo = mBarringInfo.get(phoneId);
+ BarringInfo barringInfo = mBarringInfo.get(r.phoneId);
BarringInfo biNoLocation = barringInfo != null
? barringInfo.createLocationInfoSanitizedCopy() : null;
if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
@@ -1319,8 +1323,8 @@
r.callback.onPhysicalChannelConfigChanged(
shouldSanitizeLocationForPhysicalChannelConfig(r)
? getLocationSanitizedConfigs(
- mPhysicalChannelConfigs.get(phoneId))
- : mPhysicalChannelConfigs.get(phoneId));
+ mPhysicalChannelConfigs.get(r.phoneId))
+ : mPhysicalChannelConfigs.get(r.phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1329,7 +1333,7 @@
TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)) {
try {
r.callback.onDataEnabledChanged(
- mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]);
+ mIsDataEnabled[r.phoneId], mDataEnabledReason[r.phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1337,9 +1341,9 @@
if (events.contains(
TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) {
try {
- if (mLinkCapacityEstimateLists.get(phoneId) != null) {
+ if (mLinkCapacityEstimateLists.get(r.phoneId) != null) {
r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists
- .get(phoneId));
+ .get(r.phoneId));
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1581,7 +1585,7 @@
}
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
ServiceState stateToSend;
@@ -1643,7 +1647,7 @@
if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
&& r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
if (DBG) {
log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
@@ -1654,7 +1658,7 @@
if ((activationType == SIM_ACTIVATION_TYPE_DATA)
&& r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
if (DBG) {
log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
@@ -1696,7 +1700,7 @@
TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
|| r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG) {
log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r
@@ -1710,7 +1714,7 @@
}
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -1757,7 +1761,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onCarrierNetworkChange(active);
} catch (RemoteException ex) {
@@ -1789,7 +1793,7 @@
for (Record r : mRecords) {
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)
- && idMatch(r.subId, subId, phoneId)
+ && idMatch(r, subId, phoneId)
&& (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
@@ -1823,7 +1827,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onMessageWaitingIndicatorChanged(mwi);
} catch (RemoteException ex) {
@@ -1850,7 +1854,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onUserMobileDataStateChanged(state);
} catch (RemoteException ex) {
@@ -1889,7 +1893,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)
- && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported(
r.callingPackage, Binder.getCallingUserHandle())) {
@@ -1940,7 +1944,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onCallForwardingIndicatorChanged(cfi);
} catch (RemoteException ex) {
@@ -1969,7 +1973,7 @@
// Notify by correct subId.
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onDataActivity(state);
} catch (RemoteException ex) {
@@ -2017,7 +2021,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG) {
log("Notify data connection state changed on sub: " + subId);
@@ -2042,7 +2046,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onPreciseDataConnectionStateChanged(preciseState);
} catch (RemoteException ex) {
@@ -2089,7 +2093,7 @@
for (Record r : mRecords) {
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)
- && idMatch(r.subId, subId, phoneId)
+ && idMatch(r, subId, phoneId)
&& (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
@@ -2143,7 +2147,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
} catch (RemoteException ex) {
@@ -2152,7 +2156,7 @@
}
if (notifyCallAttributes && r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
} catch (RemoteException ex) {
@@ -2177,7 +2181,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
mCallPreciseDisconnectCause[phoneId]);
@@ -2202,7 +2206,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG_LOC) {
log("notifyImsCallDisconnectCause: mImsReasonInfo="
@@ -2234,7 +2238,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG_LOC) {
log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r);
@@ -2263,7 +2267,7 @@
}
if ((r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_OEM_HOOK_RAW))
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onOemHookRawEvent(rawData);
} catch (RemoteException ex) {
@@ -2343,7 +2347,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onRadioPowerStateChanged(state);
} catch (RemoteException ex) {
@@ -2372,7 +2376,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
if (VDBG) {
@@ -2459,7 +2463,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
} catch (RemoteException ex) {
@@ -2490,7 +2494,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_REGISTRATION_FAILURE)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onRegistrationFailed(
checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
@@ -2533,7 +2537,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_BARRING_INFO_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG_LOC) {
log("notifyBarringInfo: mBarringInfo="
@@ -2578,7 +2582,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (DBG_LOC) {
log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs="
@@ -2645,7 +2649,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onDataEnabledChanged(enabled, reason);
} catch (RemoteException ex) {
@@ -2680,7 +2684,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
if (VDBG) {
log("notifyAllowedNetworkTypesChanged: reason= " + reason
@@ -2722,7 +2726,7 @@
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)
- && idMatch(r.subId, subId, phoneId)) {
+ && idMatch(r, subId, phoneId)) {
try {
r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList);
} catch (RemoteException ex) {
@@ -3172,33 +3176,24 @@
}
/**
- * If the registrant specified a subId, then we should only notify it if subIds match.
- * If the registrant registered with DEFAULT subId, we should notify only when the related subId
- * is default subId (which could be INVALID if there's no default subId).
+ * Match the sub id or phone id of the event to the record
*
- * This should be the correct way to check record ID match. in idMatch the record's phoneId is
- * speculated based on subId passed by the registrant so it's not a good reference.
- * But to avoid triggering potential regression only replace idMatch with it when an issue with
- * idMatch is reported. Eventually this should replace all instances of idMatch.
+ * We follow the rules below:
+ * 1) If sub id of the event is invalid, phone id should be used.
+ * 2) The event on default sub should be notified to the records
+ * which register the default sub id.
+ * 3) Sub id should be exactly matched for all other cases.
*/
- private boolean idMatchWithoutDefaultPhoneCheck(int subIdInRecord, int subIdToNotify) {
- if (subIdInRecord == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
- return (subIdToNotify == mDefaultSubId);
- } else {
- return (subIdInRecord == subIdToNotify);
- }
- }
+ boolean idMatch(Record r, int subId, int phoneId) {
- boolean idMatch(int rSubId, int subId, int phoneId) {
-
- if(subId < 0) {
- // Invalid case, we need compare phoneId with default one.
- return (mDefaultPhoneId == phoneId);
+ if (subId < 0) {
+ // Invalid case, we need compare phoneId.
+ return (r.phoneId == phoneId);
}
- if(rSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+ if (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
return (subId == mDefaultSubId);
} else {
- return (rSubId == subId);
+ return (r.subId == subId);
}
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index a03425c..b48e21e 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -681,7 +681,7 @@
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
mUserAllContext.registerReceiver(
- mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler, Context.RECEIVER_EXPORTED);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a2fec27..a29a49c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4906,7 +4906,9 @@
sr.setProcess(null, null, 0, null);
sr.isolatedProc = null;
sr.executeNesting = 0;
- sr.forceClearTracker();
+ synchronized (mAm.mProcessStats.mLock) {
+ sr.forceClearTracker();
+ }
if (mDestroyingServices.remove(sr)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
@@ -5056,7 +5058,9 @@
i--;
ServiceRecord sr = mDestroyingServices.get(i);
if (sr.app == app) {
- sr.forceClearTracker();
+ synchronized (mAm.mProcessStats.mLock) {
+ sr.forceClearTracker();
+ }
mDestroyingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 2f20efb..3ccacd8 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -87,6 +87,7 @@
DeviceConfig.NAMESPACE_LMKD_NATIVE,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
+ DeviceConfig.NAMESPACE_NNAPI_NATIVE,
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8e1b06b..d75f21c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6136,6 +6136,11 @@
if (pkgName == null) {
pkgName = "";
}
+ if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
+ avrcpSupportsAbsoluteVolume(device.getAddress(),
+ deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ return;
+ }
int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
device.getType());
@@ -7792,7 +7797,7 @@
}
}
- public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
+ private void avrcpSupportsAbsoluteVolume(String address, boolean support) {
// address is not used for now, but may be used when multiple a2dp devices are supported
sVolumeLogger.log(new AudioEventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr="
+ address + " support=" + support));
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 091e6c4..a56a8ea 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -227,7 +227,7 @@
subscriberId = tele.getSubscriberId();
mNetworkTemplate = new NetworkTemplate(
NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
- null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
mUsageCallback = new UsageCallback() {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 565c9ae..243a336b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1270,6 +1270,9 @@
capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
}
+ capsBuilder.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
+ ? Arrays.asList(mConfig.underlyingNetworks) : null);
+
mNetworkCapabilities = capsBuilder.build();
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp,
@@ -1290,8 +1293,6 @@
} finally {
Binder.restoreCallingIdentity(token);
}
- mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
- ? Arrays.asList(mConfig.underlyingNetworks) : null);
updateState(DetailedState.CONNECTED, "agentConnect");
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d66d7ee..329a696 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -512,7 +512,10 @@
*/
public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
synchronized (mLock) {
- mAlwaysRespectAppRequest = enabled;
+ if (mAlwaysRespectAppRequest != enabled) {
+ mAlwaysRespectAppRequest = enabled;
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index a2cb78d..c27293c 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -209,6 +209,12 @@
void init() {
assertRunOnServiceThread();
mPreferredAddress = getPreferredAddress();
+ if (mHandler.hasMessages(MSG_DISABLE_DEVICE_TIMEOUT)) {
+ // Remove and trigger the queued message for clearing all actions when going to standby.
+ // This is necessary because the device may wake up before the message is triggered.
+ mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT);
+ handleDisableDeviceTimeout();
+ }
mPendingActionClearedCallback = null;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index e5a8a17d..a571dc0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3131,7 +3131,7 @@
Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType);
devices.remove(device);
if (devices.isEmpty()) {
- onStandbyCompleted(standbyAction);
+ onPendingActionsCleared(standbyAction);
// We will not clear local devices here, since some OEM/SOC will keep passing
// the received packets until the application processor enters to the sleep
// actually.
@@ -3193,10 +3193,17 @@
mHdmiCecNetwork.clearLocalDevices();
}
+ /**
+ * Normally called after all devices have cleared their pending actions, to execute the final
+ * phase of the standby flow.
+ *
+ * This can also be called during wakeup, when pending actions are cleared after failing to be
+ * cleared during standby. In this case, it does not execute the standby flow.
+ */
@ServiceThreadOnly
- private void onStandbyCompleted(int standbyAction) {
+ private void onPendingActionsCleared(int standbyAction) {
assertRunOnServiceThread();
- Slog.v(TAG, "onStandbyCompleted");
+ Slog.v(TAG, "onPendingActionsCleared");
if (!mPowerStatusController.isPowerStatusTransientToStandby()) {
return;
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 3233819..babe21c 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -3,11 +3,9 @@
jsharkey@android.com
jsharkey@google.com
narayan@google.com
-patb@google.com
svetoslavganov@android.com
svetoslavganov@google.com
-toddke@android.com
-toddke@google.com
+include /PACKAGE_MANAGER_OWNERS
# apex support
per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f6acad0..827dfc0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7337,9 +7337,16 @@
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
+ final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
+ for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+ for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
+ }
+ }
mOverlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPmInternal.forEachPackage(
- pkg -> consumer.accept(pkg, pkg.isSystem())));
+ pkg -> consumer.accept(pkg, pkg.isSystem(),
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index dab980a..7bea018 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -213,6 +213,7 @@
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING);
+ NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.NEARBY_WIFI_DEVICES);
}
private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index 6366280..7ffff93 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -429,15 +429,7 @@
private static @NonNull
HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) {
if (dataSize > 0) {
- // Extract a dup of the underlying FileDescriptor out of data.
- FileDescriptor fd = new FileDescriptor();
- try {
- ParcelFileDescriptor dup = data.dup();
- fd.setInt$(dup.detachFd());
- return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ return HidlMemoryUtil.fileDescriptorToHidlMemory(data.getFileDescriptor(), dataSize);
} else {
return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0);
}
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 61770ea..68b760a 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -29,6 +29,7 @@
import static android.net.NetworkIdentity.OEM_PRIVATE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
@@ -1340,7 +1341,7 @@
@Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
final NetworkTemplate template = (transport == TRANSPORT_CELLULAR)
? NetworkTemplate.buildTemplateMobileWithRatType(
- /*subscriptionId=*/null, NETWORK_TYPE_ALL)
+ /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES)
: NetworkTemplate.buildTemplateWifiWildcard();
return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
}
@@ -1380,7 +1381,8 @@
final List<NetworkStatsExt> ret = new ArrayList<>();
for (final int ratType : getAllCollapsedRatTypes()) {
final NetworkTemplate template =
- buildTemplateMobileWithRatType(subInfo.subscriberId, ratType);
+ buildTemplateMobileWithRatType(subInfo.subscriberId, ratType,
+ METERED_YES);
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
if (stats != null) {
@@ -1601,7 +1603,7 @@
int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) {
BluetoothActivityEnergyInfo info = fetchBluetoothData();
- if (info == null || info.getUidTraffic() == null) {
+ if (info == null) {
return StatsManager.PULL_SKIP;
}
for (UidTraffic traffic : info.getUidTraffic()) {
@@ -2059,7 +2061,7 @@
if (info == null) {
return StatsManager.PULL_SKIP;
}
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimeStamp(),
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimestampMillis(),
info.getBluetoothStackState(), info.getControllerTxTimeMillis(),
info.getControllerRxTimeMillis(), info.getControllerIdleTimeMillis(),
info.getControllerEnergyUsed()));
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 92e0845..f57a852 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1075,17 +1075,22 @@
}
if (shouldRecreateAudioPatch) {
mCommittedVolume = volume;
- if (mAudioPatch != null) {
- mAudioManager.releaseAudioPatch(mAudioPatch);
- }
- mAudioManager.createAudioPatch(
+ // only recreate if something was updated or audioPath is null
+ if (mAudioPatch == null || sinkUpdated ||sourceUpdated ) {
+ if (mAudioPatch != null) {
+ mAudioManager.releaseAudioPatch(mAudioPatch);
+ audioPatchArray[0] = null;
+ }
+ mAudioManager.createAudioPatch(
audioPatchArray,
new AudioPortConfig[] { sourceConfig },
sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()]));
- mAudioPatch = audioPatchArray[0];
- if (sourceGainConfig != null) {
- mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
+ mAudioPatch = audioPatchArray[0];
}
+ }
+
+ if (sourceGainConfig != null) {
+ mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5540cc5..4857fb3 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1547,7 +1547,9 @@
// activity as it could lead to incorrect display metrics. For ex, IME services
// expect their config to match the config of the display with the IME window
// showing.
+ // If the configuration has been overridden by previous activity, empty it.
mIsActivityConfigOverrideAllowed = false;
+ unregisterActivityConfigurationListener();
break;
default:
break;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 2722b8d..710a304 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -165,7 +165,7 @@
"android.hardware.power@1.1",
"android.hardware.power-V2-cpp",
"android.hardware.power.stats@1.0",
- "android.hardware.power.stats-V1-ndk_platform",
+ "android.hardware.power.stats-V1-ndk",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
"android.hardware.vibrator-V2-cpp",
@@ -178,7 +178,7 @@
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
"android.system.suspend.control-V1-cpp",
"android.system.suspend.control.internal-cpp",
"android.system.suspend-V1-ndk",
diff --git a/services/tests/PackageManagerServiceTests/OWNERS b/services/tests/PackageManagerServiceTests/OWNERS
index 182dfe8..86ae581 100644
--- a/services/tests/PackageManagerServiceTests/OWNERS
+++ b/services/tests/PackageManagerServiceTests/OWNERS
@@ -1,3 +1 @@
-chiuwinson@google.com
-patb@google.com
-toddke@google.com
+include /PACKAGE_MANAGER_OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
index cb12ba7..a2ecbc3 100644
--- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
@@ -47,7 +47,6 @@
@Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier;
BatteryService.HealthServiceWrapper mWrapper;
- private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD;
private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR;
@Override
@@ -117,7 +116,7 @@
@SmallTest
public void testWrapPreferVendor() throws Exception {
- initForInstances(VENDOR, HEALTHD);
+ initForInstances(VENDOR);
mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
waitHandlerThreadFinish();
verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
@@ -126,16 +125,6 @@
}
@SmallTest
- public void testUseHealthd() throws Exception {
- initForInstances(HEALTHD);
- mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- waitHandlerThreadFinish();
- verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
- verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
- verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD));
- }
-
- @SmallTest
public void testNoService() throws Exception {
initForInstances("unrelated");
try {
diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS
index f1402ea..6a7d298 100644
--- a/services/tests/servicestests/src/com/android/server/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/OWNERS
@@ -3,4 +3,5 @@
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
+per-file BatteryServiceTest.java = file:platform/hardware/interfaces:/health/aidl/OWNERS
per-file GestureLauncherServiceTest.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 255a612..a1bed29 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2945,7 +2945,12 @@
* currently in use on the device for data transmission.
*
* If this object has been created with {@link #createForSubscriptionId}, applies to the given
- * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * subId. Otherwise, applies to {@link SubscriptionManager#getActiveDataSubscriptionId()}.
+ *
+ * Note: Before {@link SubscriptionManager#getActiveDataSubscriptionId()} was introduced in API
+ * level 30, it was applied to {@link SubscriptionManager#getDefaultDataSubscriptionId()} which
+ * may be different now from {@link SubscriptionManager#getActiveDataSubscriptionId()}, e.g.
+ * when opportunistic network is providing cellular internet connection to the user.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index e890acb..9572154 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -36,6 +36,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -152,16 +153,9 @@
throw new RuntimeException(
"Failed to find NetworkScanInfo with id " + message.arg2);
}
- NetworkScanCallback callback = nsi.mCallback;
- Executor executor = nsi.mExecutor;
- if (callback == null) {
- throw new RuntimeException(
- "Failed to find NetworkScanCallback with id " + message.arg2);
- }
- if (executor == null) {
- throw new RuntimeException(
- "Failed to find Executor with id " + message.arg2);
- }
+
+ final NetworkScanCallback callback = nsi.mCallback;
+ final Executor executor = nsi.mExecutor;
switch (message.what) {
case CALLBACK_RESTRICTED_SCAN_RESULTS:
@@ -246,17 +240,24 @@
NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
String callingPackage, @Nullable String callingFeatureId) {
try {
+ Objects.requireNonNull(request, "Request was null");
+ Objects.requireNonNull(callback, "Callback was null");
+ Objects.requireNonNull(executor, "Executor was null");
final ITelephony telephony = getITelephony();
if (telephony == null) return null;
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage,
- callingFeatureId);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
- }
+ // The lock must be taken before calling requestNetworkScan because the resulting
+ // scanId can be invoked asynchronously on another thread at any time after
+ // requestNetworkScan invoked, leaving a critical section between that call and adding
+ // the record to the ScanInfo cache.
synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage,
+ callingFeatureId);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
// We link to death whenever a scan is started to ensure that we are linked
// at the point that phone process death might matter.
// We never unlink because: