diff options
9 files changed, 521 insertions, 160 deletions
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index 675c8f80add2..a23845fa17e9 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -100,6 +100,7 @@ package android.nfc { method public void onHceEventReceived(int); method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String); method public void onLaunchHceTapAgainDialog(@NonNull android.nfc.cardemulation.ApduServiceInfo, @NonNull String); + method public void onLogEventNotified(@NonNull android.nfc.OemLogItems); method public void onNdefMessage(@NonNull android.nfc.Tag, @NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onNdefRead(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onReaderOptionChanged(boolean); @@ -115,6 +116,27 @@ package android.nfc { method public int getNfceeId(); } + @FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable { + method public int describeContents(); + method public int getAction(); + method public int getCallingPid(); + method @Nullable public byte[] getCommandApdu(); + method public int getEvent(); + method @Nullable public byte[] getResponseApdu(); + method @Nullable public java.time.Instant getRfFieldEventTimeMillis(); + method @Nullable public android.nfc.Tag getTag(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.OemLogItems> CREATOR; + field public static final int EVENT_DISABLE = 2; // 0x2 + field public static final int EVENT_ENABLE = 1; // 0x1 + field public static final int EVENT_UNSET = 0; // 0x0 + field public static final int LOG_ACTION_HCE_DATA = 516; // 0x204 + field public static final int LOG_ACTION_NFC_TOGGLE = 513; // 0x201 + field public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 1; // 0x1 + field public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 518; // 0x206 + field public static final int LOG_ACTION_TAG_DETECTED = 3; // 0x3 + } + @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingStatus { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultIsoDepRoute(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultOffHostRoute(); diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl index 7f1fd15fe68a..b102e873d737 100644 --- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl +++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl @@ -18,6 +18,7 @@ package android.nfc; import android.content.ComponentName; import android.nfc.cardemulation.ApduServiceInfo; import android.nfc.NdefMessage; +import android.nfc.OemLogItems; import android.nfc.Tag; import android.os.ResultReceiver; @@ -51,4 +52,5 @@ interface INfcOemExtensionCallback { void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent); void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category); void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category); + void onLogEventNotified(in OemLogItems item); } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 1bfe71461ac3..abd99bc02f55 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -392,6 +392,12 @@ public final class NfcOemExtension { * @param category the category of the service */ void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category); + + /** + * Callback when OEM specified log event are notified. + * @param item the log items that contains log information of NFC event. + */ + void onLogEventNotified(@NonNull OemLogItems item); } @@ -900,6 +906,12 @@ public final class NfcOemExtension { handleVoid2ArgCallback(service, category, cb::onLaunchHceTapAgainDialog, ex)); } + @Override + public void onLogEventNotified(OemLogItems item) throws RemoteException { + mCallbackMap.forEach((cb, ex) -> + handleVoidCallback(item, cb::onLogEventNotified, ex)); + } + private <T> void handleVoidCallback( T input, Consumer<T> callbackMethod, Executor executor) { synchronized (mLock) { diff --git a/nfc/java/android/nfc/OemLogItems.aidl b/nfc/java/android/nfc/OemLogItems.aidl new file mode 100644 index 000000000000..3bcb445fc7d2 --- /dev/null +++ b/nfc/java/android/nfc/OemLogItems.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 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.nfc; + +parcelable OemLogItems;
\ No newline at end of file diff --git a/nfc/java/android/nfc/OemLogItems.java b/nfc/java/android/nfc/OemLogItems.java new file mode 100644 index 000000000000..6671941c1cc9 --- /dev/null +++ b/nfc/java/android/nfc/OemLogItems.java @@ -0,0 +1,325 @@ +/*
+ * Copyright 2024 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.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+
+/**
+ * A log class for OEMs to get log information of NFC events.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class OemLogItems implements Parcelable {
+ /**
+ * Used when RF field state is changed.
+ */
+ public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 0X01;
+ /**
+ * Used when NFC is toggled. Event should be set to {@link LogEvent#EVENT_ENABLE} or
+ * {@link LogEvent#EVENT_DISABLE} if this action is used.
+ */
+ public static final int LOG_ACTION_NFC_TOGGLE = 0x0201;
+ /**
+ * Used when sending host routing status.
+ */
+ public static final int LOG_ACTION_HCE_DATA = 0x0204;
+ /**
+ * Used when screen state is changed.
+ */
+ public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 0x0206;
+ /**
+ * Used when tag is detected.
+ */
+ public static final int LOG_ACTION_TAG_DETECTED = 0x03;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = { "LOG_ACTION_" }, value = {
+ LOG_ACTION_RF_FIELD_STATE_CHANGED,
+ LOG_ACTION_NFC_TOGGLE,
+ LOG_ACTION_HCE_DATA,
+ LOG_ACTION_SCREEN_STATE_CHANGED,
+ LOG_ACTION_TAG_DETECTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LogAction {}
+
+ /**
+ * Represents the event is not set.
+ */
+ public static final int EVENT_UNSET = 0;
+ /**
+ * Represents nfc enable is called.
+ */
+ public static final int EVENT_ENABLE = 1;
+ /**
+ * Represents nfc disable is called.
+ */
+ public static final int EVENT_DISABLE = 2;
+ /** @hide */
+ @IntDef(prefix = { "EVENT_" }, value = {
+ EVENT_UNSET,
+ EVENT_ENABLE,
+ EVENT_DISABLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LogEvent {}
+ private int mAction;
+ private int mEvent;
+ private int mCallingPid;
+ private byte[] mCommandApdus;
+ private byte[] mResponseApdus;
+ private Instant mRfFieldOnTime;
+ private Tag mTag;
+
+ /** @hide */
+ public OemLogItems(@LogAction int action, @LogEvent int event, int callingPid,
+ byte[] commandApdus, byte[] responseApdus, Instant rfFieldOnTime,
+ Tag tag) {
+ mAction = action;
+ mEvent = event;
+ mTag = tag;
+ mCallingPid = callingPid;
+ mCommandApdus = commandApdus;
+ mResponseApdus = responseApdus;
+ mRfFieldOnTime = rfFieldOnTime;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable
+ * instance's marshaled representation. For example, if the object will
+ * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},
+ * the return value of this method must include the
+ * {@link #CONTENTS_FILE_DESCRIPTOR} bit.
+ *
+ * @return a bitmask indicating the set of special object types marshaled
+ * by this Parcelable object instance.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mAction);
+ dest.writeInt(mEvent);
+ dest.writeInt(mCallingPid);
+ dest.writeInt(mCommandApdus.length);
+ dest.writeByteArray(mCommandApdus);
+ dest.writeInt(mResponseApdus.length);
+ dest.writeByteArray(mResponseApdus);
+ dest.writeLong(mRfFieldOnTime.getEpochSecond());
+ dest.writeInt(mRfFieldOnTime.getNano());
+ dest.writeParcelable(mTag, 0);
+ }
+
+ /** @hide */
+ public static class Builder {
+ private final OemLogItems mItem;
+
+ public Builder(@LogAction int type) {
+ mItem = new OemLogItems(type, EVENT_UNSET, 0, new byte[0], new byte[0], null, null);
+ }
+
+ /** Setter of the log action. */
+ public OemLogItems.Builder setAction(@LogAction int action) {
+ mItem.mAction = action;
+ return this;
+ }
+
+ /** Setter of the log calling event. */
+ public OemLogItems.Builder setCallingEvent(@LogEvent int event) {
+ mItem.mEvent = event;
+ return this;
+ }
+
+ /** Setter of the log calling Pid. */
+ public OemLogItems.Builder setCallingPid(int pid) {
+ mItem.mCallingPid = pid;
+ return this;
+ }
+
+ /** Setter of APDU command. */
+ public OemLogItems.Builder setApduCommand(byte[] apdus) {
+ mItem.mCommandApdus = apdus;
+ return this;
+ }
+
+ /** Setter of RF field on time. */
+ public OemLogItems.Builder setRfFieldOnTime(Instant time) {
+ mItem.mRfFieldOnTime = time;
+ return this;
+ }
+
+ /** Setter of APDU response. */
+ public OemLogItems.Builder setApduResponse(byte[] apdus) {
+ mItem.mResponseApdus = apdus;
+ return this;
+ }
+
+ /** Setter of dispatched tag. */
+ public OemLogItems.Builder setTag(Tag tag) {
+ mItem.mTag = tag;
+ return this;
+ }
+
+ /** Builds an {@link OemLogItems} instance. */
+ public OemLogItems build() {
+ return mItem;
+ }
+ }
+
+ /**
+ * Gets the action of this log.
+ * @return one of {@link LogAction}
+ */
+ @LogAction
+ public int getAction() {
+ return mAction;
+ }
+
+ /**
+ * Gets the event of this log. This will be set to {@link LogEvent#EVENT_ENABLE} or
+ * {@link LogEvent#EVENT_DISABLE} only when action is set to
+ * {@link LogAction#LOG_ACTION_NFC_TOGGLE}
+ * @return one of {@link LogEvent}
+ */
+ @LogEvent
+ public int getEvent() {
+ return mEvent;
+ }
+
+ /**
+ * Gets the calling Pid of this log. This field will be set only when action is set to
+ * {@link LogAction#LOG_ACTION_NFC_TOGGLE}
+ * @return calling Pid
+ */
+ public int getCallingPid() {
+ return mCallingPid;
+ }
+
+ /**
+ * Gets the command APDUs of this log. This field will be set only when action is set to
+ * {@link LogAction#LOG_ACTION_HCE_DATA}
+ * @return a byte array of command APDUs with the same format as
+ * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])}
+ */
+ @Nullable
+ public byte[] getCommandApdu() {
+ return mCommandApdus;
+ }
+
+ /**
+ * Gets the response APDUs of this log. This field will be set only when action is set to
+ * {@link LogAction#LOG_ACTION_HCE_DATA}
+ * @return a byte array of response APDUs with the same format as
+ * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])}
+ */
+ @Nullable
+ public byte[] getResponseApdu() {
+ return mResponseApdus;
+ }
+
+ /**
+ * Gets the RF field event time in this log in millisecond. This field will be set only when
+ * action is set to {@link LogAction#LOG_ACTION_RF_FIELD_STATE_CHANGED}
+ * @return an {@link Instant} of RF field event time.
+ */
+ @Nullable
+ public Instant getRfFieldEventTimeMillis() {
+ return mRfFieldOnTime;
+ }
+
+ /**
+ * Gets the tag of this log. This field will be set only when action is set to
+ * {@link LogAction#LOG_ACTION_TAG_DETECTED}
+ * @return a detected {@link Tag} in {@link #LOG_ACTION_TAG_DETECTED} case. Return
+ * null otherwise.
+ */
+ @Nullable
+ public Tag getTag() {
+ return mTag;
+ }
+
+ private String byteToHex(byte[] bytes) {
+ char[] HexArray = "0123456789ABCDEF".toCharArray();
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = HexArray[v >>> 4];
+ hexChars[j * 2 + 1] = HexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ @Override
+ public String toString() {
+ return "[mCommandApdus: "
+ + ((mCommandApdus != null) ? byteToHex(mCommandApdus) : "null")
+ + "[mResponseApdus: "
+ + ((mResponseApdus != null) ? byteToHex(mResponseApdus) : "null")
+ + ", mCallingApi= " + mEvent
+ + ", mAction= " + mAction
+ + ", mCallingPId = " + mCallingPid
+ + ", mRfFieldOnTime= " + mRfFieldOnTime;
+ }
+ private OemLogItems(Parcel in) {
+ this.mAction = in.readInt();
+ this.mEvent = in.readInt();
+ this.mCallingPid = in.readInt();
+ this.mCommandApdus = new byte[in.readInt()];
+ in.readByteArray(this.mCommandApdus);
+ this.mResponseApdus = new byte[in.readInt()];
+ in.readByteArray(this.mResponseApdus);
+ this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
+ this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class);
+ }
+
+ public static final @NonNull Parcelable.Creator<OemLogItems> CREATOR =
+ new Parcelable.Creator<OemLogItems>() {
+ @Override
+ public OemLogItems createFromParcel(Parcel in) {
+ return new OemLogItems(in);
+ }
+
+ @Override
+ public OemLogItems[] newArray(int size) {
+ return new OemLogItems[size];
+ }
+ };
+
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 6fb5598ee568..a916237364b4 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -39,6 +39,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.content.Intent; +import android.media.AudioDescriptor; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioDevicePort; @@ -46,6 +47,7 @@ import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioManager.AudioDeviceCategory; import android.media.AudioPort; +import android.media.AudioProfile; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; @@ -611,6 +613,8 @@ public class AudioDeviceInventory { final int mGroupId; @NonNull String mPeerDeviceAddress; @NonNull String mPeerIdentityDeviceAddress; + @NonNull List<AudioProfile> mAudioProfiles; + @NonNull List<AudioDescriptor> mAudioDescriptors; /** Disabled operating modes for this device. Use a negative logic so that by default * an empty list means all modes are allowed. @@ -619,7 +623,8 @@ public class AudioDeviceInventory { DeviceInfo(int deviceType, String deviceName, String address, String identityAddress, int codecFormat, - int groupId, String peerAddress, String peerIdentityAddress) { + int groupId, String peerAddress, String peerIdentityAddress, + List<AudioProfile> profiles, List<AudioDescriptor> descriptors) { mDeviceType = deviceType; mDeviceName = TextUtils.emptyIfNull(deviceName); mDeviceAddress = TextUtils.emptyIfNull(address); @@ -631,6 +636,16 @@ public class AudioDeviceInventory { mGroupId = groupId; mPeerDeviceAddress = TextUtils.emptyIfNull(peerAddress); mPeerIdentityDeviceAddress = TextUtils.emptyIfNull(peerIdentityAddress); + mAudioProfiles = profiles; + mAudioDescriptors = descriptors; + } + + DeviceInfo(int deviceType, String deviceName, String address, + String identityAddress, int codecFormat, + int groupId, String peerAddress, String peerIdentityAddress) { + this(deviceType, deviceName, address, identityAddress, codecFormat, + groupId, peerAddress, peerIdentityAddress, + new ArrayList<>(), new ArrayList<>()); } /** Constructor for all devices except A2DP sink and LE Audio */ @@ -638,6 +653,13 @@ public class AudioDeviceInventory { this(deviceType, deviceName, address, null, AudioSystem.AUDIO_FORMAT_DEFAULT); } + /** Constructor for HDMI OUT, HDMI ARC/EARC sink devices */ + DeviceInfo(int deviceType, String deviceName, String address, + List<AudioProfile> profiles, List<AudioDescriptor> descriptors) { + this(deviceType, deviceName, address, null, AudioSystem.AUDIO_FORMAT_DEFAULT, + BluetoothLeAudio.GROUP_ID_INVALID, null, null, profiles, descriptors); + } + /** Constructor for A2DP sink devices */ DeviceInfo(int deviceType, String deviceName, String address, String identityAddress, int codecFormat) { @@ -1172,27 +1194,31 @@ public class AudioDeviceInventory { } /*package*/ void onToggleHdmi() { - MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "onToggleHdmi") - .set(MediaMetrics.Property.DEVICE, - AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HDMI)); + final int[] hdmiDevices = { AudioSystem.DEVICE_OUT_HDMI, + AudioSystem.DEVICE_OUT_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_EARC }; + synchronized (mDevicesLock) { - // Is HDMI connected? - final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, ""); - final DeviceInfo di = mConnectedDevices.get(key); - if (di == null) { - Log.e(TAG, "invalid null DeviceInfo in onToggleHdmi"); - mmi.set(MediaMetrics.Property.EARLY_RETURN, "invalid null DeviceInfo").record(); - return; + for (DeviceInfo di : mConnectedDevices.values()) { + boolean isHdmiDevice = Arrays.stream(hdmiDevices).anyMatch(device -> + device == di.mDeviceType); + if (isHdmiDevice) { + MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "onToggleHdmi") + .set(MediaMetrics.Property.DEVICE, + AudioSystem.getDeviceName(di.mDeviceType)); + AudioDeviceAttributes ada = new AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.convertInternalDeviceToDeviceType(di.mDeviceType), + di.mDeviceAddress, di.mDeviceName, di.mAudioProfiles, + di.mAudioDescriptors); + // Toggle HDMI to retrigger broadcast with proper formats. + setWiredDeviceConnectionState(ada, + AudioSystem.DEVICE_STATE_UNAVAILABLE, "onToggleHdmi"); // disconnect + setWiredDeviceConnectionState(ada, + AudioSystem.DEVICE_STATE_AVAILABLE, "onToggleHdmi"); // reconnect + mmi.record(); + } } - // Toggle HDMI to retrigger broadcast with proper formats. - setWiredDeviceConnectionState( - new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""), - AudioSystem.DEVICE_STATE_UNAVAILABLE, "android"); // disconnect - setWiredDeviceConnectionState( - new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""), - AudioSystem.DEVICE_STATE_AVAILABLE, "android"); // reconnect } - mmi.record(); } @GuardedBy("mDevicesLock") @@ -1787,7 +1813,15 @@ public class AudioDeviceInventory { .printSlog(EventLogger.Event.ALOGE, TAG)); return false; } - mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address)); + + if (device == AudioSystem.DEVICE_OUT_HDMI || + device == AudioSystem.DEVICE_OUT_HDMI_ARC || + device == AudioSystem.DEVICE_OUT_HDMI_EARC) { + mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, + address, attributes.getAudioProfiles(), attributes.getAudioDescriptors())); + } else { + mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address)); + } mDeviceBroker.postAccessoryPlugMediaUnmute(device); status = true; } else if (!connect && isConnected) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 2a3be1e119bf..7de2815eba6b 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -513,12 +513,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private boolean mLoadedRestrictBackground; /** - * Whether or not network for apps in proc-states greater than - * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} is always blocked. - */ - private boolean mBackgroundNetworkRestricted; - - /** * Whether or not metered firewall chains should be used for uid policy controlling access to * metered networks. */ @@ -1117,14 +1111,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writePolicyAL(); } - // The flag is boot-stable. - mBackgroundNetworkRestricted = Flags.networkBlockedForTopSleepingAndAbove(); - if (mBackgroundNetworkRestricted) { - // Firewall rules and UidBlockedState will get updated in - // updateRulesForGlobalChangeAL below. - enableFirewallChainUL(FIREWALL_CHAIN_BACKGROUND, true); - } - + enableFirewallChainUL(FIREWALL_CHAIN_BACKGROUND, true); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); @@ -1135,11 +1122,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int changes = ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_CAPABILITY; - - final int cutpoint = mBackgroundNetworkRestricted ? PROCESS_STATE_UNKNOWN - : NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE; mActivityManagerInternal.registerNetworkPolicyUidObserver(mUidObserver, changes, - cutpoint, "android"); + PROCESS_STATE_UNKNOWN, "android"); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server @@ -1280,21 +1264,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // different chains may change. return true; } - if (mBackgroundNetworkRestricted) { - if ((previousProcState >= BACKGROUND_THRESHOLD_STATE) + if ((previousProcState >= BACKGROUND_THRESHOLD_STATE) != (newProcState >= BACKGROUND_THRESHOLD_STATE)) { - // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will - // need to be re-evaluated for the background chain. - return true; - } - if (mUseDifferentDelaysForBackgroundChain - && newProcState >= BACKGROUND_THRESHOLD_STATE - && getBackgroundTransitioningDelay(newProcState) - < getBackgroundTransitioningDelay(previousProcState)) { - // The old and new proc-state both are in the blocked state but the background - // transition delay is reduced, so we may have to update the rules sooner. - return true; - } + // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will + // need to be re-evaluated for the background chain. + return true; + } + if (mUseDifferentDelaysForBackgroundChain + && newProcState >= BACKGROUND_THRESHOLD_STATE + && getBackgroundTransitioningDelay(newProcState) + < getBackgroundTransitioningDelay(previousProcState)) { + // The old and new proc-state both are in the blocked state but the background + // transition delay is reduced, so we may have to update the rules sooner. + return true; } final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK; @@ -1367,9 +1349,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected synchronized (mUidRulesFirstLock) { updatePowerSaveAllowlistUL(); - if (mBackgroundNetworkRestricted) { - updateRulesForBackgroundChainUL(); - } + updateRulesForBackgroundChainUL(); updateRulesForRestrictPowerUL(); updateRulesForAppIdleUL(); } @@ -4100,8 +4080,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.println(); fout.println("Flags:"); - fout.println(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE + ": " - + mBackgroundNetworkRestricted); fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": " + mUseMeteredFirewallChains); fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": " @@ -4251,35 +4229,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } - if (mBackgroundNetworkRestricted) { + fout.println(); + if (mUseDifferentDelaysForBackgroundChain) { + fout.print("Background restrictions short delay: "); + TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout); fout.println(); - if (mUseDifferentDelaysForBackgroundChain) { - fout.print("Background restrictions short delay: "); - TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout); - fout.println(); - fout.print("Background restrictions long delay: "); - TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout); - fout.println(); - } + fout.print("Background restrictions long delay: "); + TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout); + fout.println(); + } - size = mBackgroundTransitioningUids.size(); - if (size > 0) { - final long nowUptime = SystemClock.uptimeMillis(); - fout.println("Uids transitioning to background:"); - fout.increaseIndent(); - for (int i = 0; i < size; i++) { - fout.print("UID="); - fout.print(mBackgroundTransitioningUids.keyAt(i)); - fout.print(", "); - TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), - nowUptime, fout); - fout.println(); - } - fout.decreaseIndent(); + size = mBackgroundTransitioningUids.size(); + if (size > 0) { + final long nowUptime = SystemClock.uptimeMillis(); + fout.println("Uids transitioning to background:"); + fout.increaseIndent(); + for (int i = 0; i < size; i++) { + fout.print("UID="); + fout.print(mBackgroundTransitioningUids.keyAt(i)); + fout.print(", "); + TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), + nowUptime, fout); + fout.println(); } - fout.println(); + fout.decreaseIndent(); } + fout.println(); final SparseBooleanArray knownUids = new SparseBooleanArray(); collectKeys(mUidState, knownUids); @@ -4465,51 +4441,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } updatePowerRestrictionRules = true; } - if (mBackgroundNetworkRestricted) { - final boolean wasAllowed = isProcStateAllowedNetworkWhileBackground( - oldUidState); - final boolean isAllowed = isProcStateAllowedNetworkWhileBackground(newUidState); - if (!wasAllowed && isAllowed) { - mBackgroundTransitioningUids.delete(uid); - updateRuleForBackgroundUL(uid); - updatePowerRestrictionRules = true; - } else if (!isAllowed) { - final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid); - final long completionTimeMs = SystemClock.uptimeMillis() - + getBackgroundTransitioningDelay(procState); - boolean completionTimeUpdated = false; - if (wasAllowed) { - // Rules need to transition from allowed to blocked after the respective - // delay. - if (transitionIdx < 0) { - // This is just a defensive check in case the upstream code ever - // makes multiple calls for the same process state change. - mBackgroundTransitioningUids.put(uid, completionTimeMs); - completionTimeUpdated = true; - } - } else if (mUseDifferentDelaysForBackgroundChain) { - // wasAllowed was false, but the transition delay may have reduced. - // Currently, this can happen when the uid transitions from - // LAST_ACTIVITY to CACHED_ACTIVITY, for example. - if (transitionIdx >= 0 - && completionTimeMs < mBackgroundTransitioningUids.valueAt( - transitionIdx)) { - mBackgroundTransitioningUids.setValueAt(transitionIdx, - completionTimeMs); - completionTimeUpdated = true; - } + final boolean wasAllowed = isProcStateAllowedNetworkWhileBackground( + oldUidState); + final boolean isAllowed = isProcStateAllowedNetworkWhileBackground(newUidState); + if (!wasAllowed && isAllowed) { + mBackgroundTransitioningUids.delete(uid); + updateRuleForBackgroundUL(uid); + updatePowerRestrictionRules = true; + } else if (!isAllowed) { + final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid); + final long completionTimeMs = SystemClock.uptimeMillis() + + getBackgroundTransitioningDelay(procState); + boolean completionTimeUpdated = false; + if (wasAllowed) { + // Rules need to transition from allowed to blocked after the respective + // delay. + if (transitionIdx < 0) { + // This is just a defensive check in case the upstream code ever + // makes multiple calls for the same process state change. + mBackgroundTransitioningUids.put(uid, completionTimeMs); + completionTimeUpdated = true; } - if (completionTimeUpdated - && completionTimeMs < mNextProcessBackgroundUidsTime) { - // Many uids may be in this "transitioning" state at the same time, - // so we always keep one message to process transition completion at - // the earliest time. - mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS); - mHandler.sendEmptyMessageAtTime( - MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs); - mNextProcessBackgroundUidsTime = completionTimeMs; + } else if (mUseDifferentDelaysForBackgroundChain) { + // wasAllowed was false, but the transition delay may have reduced. + // Currently, this can happen when the uid transitions from + // LAST_ACTIVITY to CACHED_ACTIVITY, for example. + if (transitionIdx >= 0 + && completionTimeMs < mBackgroundTransitioningUids.valueAt( + transitionIdx)) { + mBackgroundTransitioningUids.setValueAt(transitionIdx, + completionTimeMs); + completionTimeUpdated = true; } } + if (completionTimeUpdated + && completionTimeMs < mNextProcessBackgroundUidsTime) { + // Many uids may be in this "transitioning" state at the same time, + // so we always keep one message to process transition completion at + // the earliest time. + mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS); + mHandler.sendEmptyMessageAtTime( + MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs); + mNextProcessBackgroundUidsTime = completionTimeMs; + } } if (mLowPowerStandbyActive) { boolean allowedInLpsChanged = @@ -4545,12 +4519,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mRestrictPower) { updateRuleForRestrictPowerUL(uid); } - if (mBackgroundNetworkRestricted) { - // Uid is no longer running, there is no point in any grace period of network - // access during transitions to lower importance proc-states. - mBackgroundTransitioningUids.delete(uid); - updateRuleForBackgroundUL(uid); - } + // Uid is no longer running, there is no point in any grace period of network + // access during transitions to lower importance proc-states. + mBackgroundTransitioningUids.delete(uid); + updateRuleForBackgroundUL(uid); updateRulesForPowerRestrictionsUL(uid); if (mLowPowerStandbyActive) { updateRuleForLowPowerStandbyUL(uid); @@ -5021,9 +4993,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { "updateRulesForGlobalChangeAL: " + (restrictedNetworksChanged ? "R" : "-")); } try { - if (mBackgroundNetworkRestricted) { - updateRulesForBackgroundChainUL(); - } + updateRulesForBackgroundChainUL(); updateRulesForAppIdleUL(); updateRulesForRestrictPowerUL(); updateRulesForRestrictBackgroundUL(); @@ -5183,9 +5153,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForDeviceIdleUL(uid); updateRuleForRestrictPowerUL(uid); - if (mBackgroundNetworkRestricted) { - updateRuleForBackgroundUL(uid); - } + updateRuleForBackgroundUL(uid); // Update internal rules. updateRulesForPowerRestrictionsUL(uid); } @@ -5358,9 +5326,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForDeviceIdleUL(uid); updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForRestrictPowerUL(uid); - if (mBackgroundNetworkRestricted) { - updateRuleForBackgroundUL(uid); - } + updateRuleForBackgroundUL(uid); // If the uid has the necessary permissions, then it should be added to the restricted mode // firewall allowlist. @@ -5611,7 +5577,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0); newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); - newBlockedReasons |= mBackgroundNetworkRestricted ? BLOCKED_REASON_APP_BACKGROUND : 0; + newBlockedReasons |= BLOCKED_REASON_APP_BACKGROUND; newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); @@ -5624,8 +5590,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS); newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid)) ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0; - newAllowedReasons |= (mBackgroundNetworkRestricted - && isUidExemptFromBackgroundRestrictions(uid)) + newAllowedReasons |= isUidExemptFromBackgroundRestrictions(uid) ? ALLOWED_REASON_NOT_IN_BACKGROUND : 0; uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig index 7f04e665567e..3c0ff6115fcd 100644 --- a/services/core/java/com/android/server/net/flags.aconfig +++ b/services/core/java/com/android/server/net/flags.aconfig @@ -2,13 +2,6 @@ package: "com.android.server.net" container: "system" flag { - name: "network_blocked_for_top_sleeping_and_above" - namespace: "backstage_power" - description: "Block network access for apps in a low importance background state" - bug: "304347838" -} - -flag { name: "use_metered_firewall_chains" namespace: "backstage_power" description: "Use metered firewall chains to control access to metered networks" diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index dddab657be14..5a7027edc20d 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -2158,13 +2158,11 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainEnabled() throws Exception { verify(mNetworkManager).setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true); } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) @RequiresFlagsDisabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN) public void testBackgroundChainOnProcStateChangeSameDelay() throws Exception { // initialization calls setFirewallChainEnabled, so we want to reset the invocations. @@ -2194,10 +2192,7 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled({ - Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE, - Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN - }) + @RequiresFlagsEnabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN) public void testBackgroundChainOnProcStateChangeDifferentDelays() throws Exception { // The app will be blocked when there is no prior proc-state. assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); @@ -2247,7 +2242,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnAllowlistChange() throws Exception { // initialization calls setFirewallChainEnabled, so we want to reset the invocations. clearInvocations(mNetworkManager); @@ -2285,7 +2279,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testBackgroundChainOnTempAllowlistChange() throws Exception { // initialization calls setFirewallChainEnabled, so we want to reset the invocations. clearInvocations(mNetworkManager); @@ -2387,7 +2380,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testUidObserverFiltersProcStateChanges() throws Exception { int testProcStateSeq = 0; try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { @@ -2450,7 +2442,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testUidObserverFiltersStaleChanges() throws Exception { final int testProcStateSeq = 51; try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { @@ -2470,7 +2461,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testUidObserverFiltersCapabilityChanges() throws Exception { int testProcStateSeq = 0; try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { @@ -2559,7 +2549,6 @@ public class NetworkPolicyManagerServiceTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testObsoleteHandleUidChanged() throws Exception { callAndWaitOnUidGone(UID_A); assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); |