Merge "Fix flakeĀ : testVpnSetUnderlyingNetworks" into main
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index ffa2857..9520ef6 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -82,6 +82,17 @@
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
+// The filegroup lists files that are necessary for verifying building mdns as a standalone,
+// for use with service-connectivity-mdns-standalone-build-test
+filegroup {
+ name: "framework-connectivity-t-mdns-standalone-build-sources",
+ srcs: [
+ "src/android/net/nsd/OffloadEngine.java",
+ "src/android/net/nsd/OffloadServiceInfo.java",
+ ],
+ visibility: ["//packages/modules/Connectivity:__subpackages__"],
+}
+
java_library {
name: "framework-connectivity-t-pre-jarjar",
defaults: ["framework-connectivity-t-defaults"],
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index 87b0a64..64762b4 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -348,3 +348,43 @@
}
+package android.net.nsd {
+
+ public final class NsdManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void registerOffloadEngine(@NonNull String, long, long, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.OffloadEngine);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void unregisterOffloadEngine(@NonNull android.net.nsd.OffloadEngine);
+ }
+
+ public interface OffloadEngine {
+ method public void onOffloadServiceRemoved(@NonNull android.net.nsd.OffloadServiceInfo);
+ method public void onOffloadServiceUpdated(@NonNull android.net.nsd.OffloadServiceInfo);
+ field public static final int OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK = 1; // 0x1
+ field public static final int OFFLOAD_TYPE_FILTER_QUERIES = 2; // 0x2
+ field public static final int OFFLOAD_TYPE_FILTER_REPLIES = 4; // 0x4
+ field public static final int OFFLOAD_TYPE_REPLY = 1; // 0x1
+ }
+
+ public final class OffloadServiceInfo implements android.os.Parcelable {
+ ctor public OffloadServiceInfo(@NonNull android.net.nsd.OffloadServiceInfo.Key, @NonNull java.util.List<java.lang.String>, @NonNull String, @Nullable byte[], @IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int, long);
+ method public int describeContents();
+ method @NonNull public String getHostname();
+ method @NonNull public android.net.nsd.OffloadServiceInfo.Key getKey();
+ method @Nullable public byte[] getOffloadPayload();
+ method public long getOffloadType();
+ method public int getPriority();
+ method @NonNull public java.util.List<java.lang.String> getSubtypes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.nsd.OffloadServiceInfo> CREATOR;
+ }
+
+ public static final class OffloadServiceInfo.Key implements android.os.Parcelable {
+ ctor public OffloadServiceInfo.Key(@NonNull String, @NonNull String);
+ method public int describeContents();
+ method @NonNull public String getServiceName();
+ method @NonNull public String getServiceType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.nsd.OffloadServiceInfo.Key> CREATOR;
+ }
+
+}
+
diff --git a/framework-t/src/android/net/nsd/INsdServiceConnector.aidl b/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
index 5533154..e671db1 100644
--- a/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
+++ b/framework-t/src/android/net/nsd/INsdServiceConnector.aidl
@@ -17,6 +17,7 @@
package android.net.nsd;
import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.IOffloadEngine;
import android.net.nsd.NsdServiceInfo;
import android.os.Messenger;
@@ -35,4 +36,6 @@
void stopResolution(int listenerKey);
void registerServiceInfoCallback(int listenerKey, in NsdServiceInfo serviceInfo);
void unregisterServiceInfoCallback(int listenerKey);
+ void registerOffloadEngine(String ifaceName, in IOffloadEngine cb, long offloadCapabilities, long offloadType);
+ void unregisterOffloadEngine(in IOffloadEngine cb);
}
\ No newline at end of file
diff --git a/framework-t/src/android/net/nsd/IOffloadEngine.aidl b/framework-t/src/android/net/nsd/IOffloadEngine.aidl
new file mode 100644
index 0000000..2af733d
--- /dev/null
+++ b/framework-t/src/android/net/nsd/IOffloadEngine.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, 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.nsd;
+
+import android.net.nsd.OffloadServiceInfo;
+
+/**
+ * Callbacks from NsdService to inform providers of packet offload.
+ *
+ * @hide
+ */
+oneway interface IOffloadEngine {
+ void onOffloadServiceUpdated(in OffloadServiceInfo info);
+ void onOffloadServiceRemoved(in OffloadServiceInfo info);
+}
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java
index 2930cbd..ef0e34b 100644
--- a/framework-t/src/android/net/nsd/NsdManager.java
+++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,9 @@
package android.net.nsd;
+import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_PLATFORM_MDNS_BACKEND;
import static android.net.connectivity.ConnectivityCompatChanges.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS_T_AND_LATER;
@@ -25,6 +28,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.compat.CompatChanges;
import android.content.Context;
@@ -45,9 +49,11 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.CollectionUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -246,6 +252,10 @@
public static final int UNREGISTER_SERVICE_CALLBACK = 31;
/** @hide */
public static final int UNREGISTER_SERVICE_CALLBACK_SUCCEEDED = 32;
+ /** @hide */
+ public static final int REGISTER_OFFLOAD_ENGINE = 33;
+ /** @hide */
+ public static final int UNREGISTER_OFFLOAD_ENGINE = 34;
/** Dns based service discovery protocol */
public static final int PROTOCOL_DNS_SD = 0x0001;
@@ -313,8 +323,107 @@
private final ArrayMap<Integer, PerNetworkDiscoveryTracker>
mPerNetworkDiscoveryMap = new ArrayMap<>();
+ @GuardedBy("mOffloadEngines")
+ private final ArrayList<OffloadEngineProxy> mOffloadEngines = new ArrayList<>();
private final ServiceHandler mHandler;
+ private static class OffloadEngineProxy extends IOffloadEngine.Stub {
+ private final Executor mExecutor;
+ private final OffloadEngine mEngine;
+
+ private OffloadEngineProxy(@NonNull Executor executor, @NonNull OffloadEngine appCb) {
+ mExecutor = executor;
+ mEngine = appCb;
+ }
+
+ @Override
+ public void onOffloadServiceUpdated(OffloadServiceInfo info) {
+ mExecutor.execute(() -> mEngine.onOffloadServiceUpdated(info));
+ }
+
+ @Override
+ public void onOffloadServiceRemoved(OffloadServiceInfo info) {
+ mExecutor.execute(() -> mEngine.onOffloadServiceRemoved(info));
+ }
+ }
+
+ /**
+ * Registers an OffloadEngine with NsdManager.
+ *
+ * A caller can register itself as an OffloadEngine if it supports mDns hardware offload.
+ * The caller must implement the {@link OffloadEngine} interface and update hardware offload
+ * state property when the {@link OffloadEngine#onOffloadServiceUpdated} and
+ * {@link OffloadEngine#onOffloadServiceRemoved} callback are called. Multiple engines may be
+ * registered for the same interface, and that the same engine cannot be registered twice.
+ *
+ * @param ifaceName indicates which network interface the hardware offload runs on
+ * @param offloadType the type of offload that the offload engine support
+ * @param offloadCapability the capabilities of the offload engine
+ * @param executor the executor on which to receive the offload callbacks
+ * @param engine the OffloadEngine that will receive the offload callbacks
+ * @throws IllegalStateException if the engine is already registered.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {NETWORK_SETTINGS, PERMISSION_MAINLINE_NETWORK_STACK,
+ NETWORK_STACK})
+ public void registerOffloadEngine(@NonNull String ifaceName,
+ @OffloadEngine.OffloadType long offloadType,
+ @OffloadEngine.OffloadCapability long offloadCapability, @NonNull Executor executor,
+ @NonNull OffloadEngine engine) {
+ Objects.requireNonNull(ifaceName);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(engine);
+ final OffloadEngineProxy cbImpl = new OffloadEngineProxy(executor, engine);
+ synchronized (mOffloadEngines) {
+ if (CollectionUtils.contains(mOffloadEngines, impl -> impl.mEngine == engine)) {
+ throw new IllegalStateException("This engine is already registered");
+ }
+ mOffloadEngines.add(cbImpl);
+ }
+ try {
+ mService.registerOffloadEngine(ifaceName, cbImpl, offloadCapability, offloadType);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Unregisters an OffloadEngine from NsdService.
+ *
+ * A caller can unregister itself as an OffloadEngine when it doesn't want to receive the
+ * callback anymore. The OffloadEngine must have been previously registered with the system
+ * using the {@link NsdManager#registerOffloadEngine} method.
+ *
+ * @param engine OffloadEngine object to be removed from NsdService
+ * @throws IllegalStateException if the engine is not registered.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {NETWORK_SETTINGS, PERMISSION_MAINLINE_NETWORK_STACK,
+ NETWORK_STACK})
+ public void unregisterOffloadEngine(@NonNull OffloadEngine engine) {
+ Objects.requireNonNull(engine);
+ final OffloadEngineProxy cbImpl;
+ synchronized (mOffloadEngines) {
+ final int index = CollectionUtils.indexOf(mOffloadEngines,
+ impl -> impl.mEngine == engine);
+ if (index < 0) {
+ throw new IllegalStateException("This engine is not registered");
+ }
+ cbImpl = mOffloadEngines.remove(index);
+ }
+
+ try {
+ mService.unregisterOffloadEngine(cbImpl);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
private class PerNetworkDiscoveryTracker {
final String mServiceType;
final int mProtocolType;
diff --git a/framework-t/src/android/net/nsd/OffloadEngine.java b/framework-t/src/android/net/nsd/OffloadEngine.java
new file mode 100644
index 0000000..b566b13
--- /dev/null
+++ b/framework-t/src/android/net/nsd/OffloadEngine.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 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.nsd;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * OffloadEngine is an interface for mDns hardware offloading.
+ *
+ * An offloading engine can interact with the firmware code to instruct the hardware to
+ * offload some of mDns network traffic before it reached android OS. This can improve the
+ * power consumption performance of the host system by not always waking up the OS to handle
+ * the mDns packet when the device is in low power mode.
+ *
+ * @hide
+ */
+@SystemApi
+public interface OffloadEngine {
+ /**
+ * Indicates that the OffloadEngine can generate replies to mDns queries.
+ *
+ * @see OffloadServiceInfo#getOffloadPayload()
+ */
+ int OFFLOAD_TYPE_REPLY = 1;
+ /**
+ * Indicates that the OffloadEngine can filter and drop mDns queries.
+ */
+ int OFFLOAD_TYPE_FILTER_QUERIES = 1 << 1;
+ /**
+ * Indicates that the OffloadEngine can filter and drop mDns replies. It can allow mDns packets
+ * to be received even when no app holds a {@link android.net.wifi.WifiManager.MulticastLock}.
+ */
+ int OFFLOAD_TYPE_FILTER_REPLIES = 1 << 2;
+
+ /**
+ * Indicates that the OffloadEngine can bypass multicast lock.
+ */
+ int OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK = 1;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @LongDef(flag = true, prefix = {"OFFLOAD_TYPE"}, value = {
+ OFFLOAD_TYPE_REPLY,
+ OFFLOAD_TYPE_FILTER_QUERIES,
+ OFFLOAD_TYPE_FILTER_REPLIES,
+ })
+ @interface OffloadType {}
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @LongDef(flag = true, prefix = {"OFFLOAD_CAPABILITY"}, value = {
+ OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK
+ })
+ @interface OffloadCapability {}
+
+ /**
+ * To be called when the OffloadServiceInfo is added or updated.
+ *
+ * @param info The OffloadServiceInfo to add or update.
+ */
+ void onOffloadServiceUpdated(@NonNull OffloadServiceInfo info);
+
+ /**
+ * To be called when the OffloadServiceInfo is removed.
+ *
+ * @param info The OffloadServiceInfo to remove.
+ */
+ void onOffloadServiceRemoved(@NonNull OffloadServiceInfo info);
+}
diff --git a/framework-t/src/android/net/nsd/OffloadServiceInfo.java b/framework-t/src/android/net/nsd/OffloadServiceInfo.java
new file mode 100644
index 0000000..7bd5a7d
--- /dev/null
+++ b/framework-t/src/android/net/nsd/OffloadServiceInfo.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2023 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.nsd;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.net.module.util.HexDump;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The OffloadServiceInfo class contains all the necessary information the OffloadEngine needs to
+ * know about how to offload an mDns service. The OffloadServiceInfo is keyed on
+ * {@link OffloadServiceInfo.Key} which is a (serviceName, serviceType) pair.
+ *
+ * @hide
+ */
+@SystemApi
+public final class OffloadServiceInfo implements Parcelable {
+ @NonNull
+ private final Key mKey;
+ @NonNull
+ private final String mHostname;
+ @NonNull final List<String> mSubtypes;
+ @Nullable
+ private final byte[] mOffloadPayload;
+ private final int mPriority;
+ private final long mOffloadType;
+
+ /**
+ * Creates a new OffloadServiceInfo object with the specified parameters.
+ *
+ * @param key The key of the service.
+ * @param subtypes The list of subTypes of the service.
+ * @param hostname The name of the host offering the service. It is meaningful only when
+ * offloadType contains OFFLOAD_REPLY.
+ * @param offloadPayload The raw udp payload for hardware offloading.
+ * @param priority The priority of the service, @see #getPriority.
+ * @param offloadType The type of the service offload, @see #getOffloadType.
+ */
+ public OffloadServiceInfo(@NonNull Key key,
+ @NonNull List<String> subtypes, @NonNull String hostname,
+ @Nullable byte[] offloadPayload,
+ @IntRange(from = 0, to = Integer.MAX_VALUE) int priority,
+ @OffloadEngine.OffloadType long offloadType) {
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(subtypes);
+ Objects.requireNonNull(hostname);
+ mKey = key;
+ mSubtypes = subtypes;
+ mHostname = hostname;
+ mOffloadPayload = offloadPayload;
+ mPriority = priority;
+ mOffloadType = offloadType;
+ }
+
+ /**
+ * Creates a new OffloadServiceInfo object from a Parcel.
+ *
+ * @param in The Parcel to read the object from.
+ *
+ * @hide
+ */
+ public OffloadServiceInfo(@NonNull Parcel in) {
+ mKey = in.readParcelable(Key.class.getClassLoader(),
+ Key.class);
+ mSubtypes = in.createStringArrayList();
+ mHostname = in.readString();
+ mOffloadPayload = in.createByteArray();
+ mPriority = in.readInt();
+ mOffloadType = in.readLong();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mKey, flags);
+ dest.writeStringList(mSubtypes);
+ dest.writeString(mHostname);
+ dest.writeByteArray(mOffloadPayload);
+ dest.writeInt(mPriority);
+ dest.writeLong(mOffloadType);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<OffloadServiceInfo> CREATOR = new Creator<OffloadServiceInfo>() {
+ @Override
+ public OffloadServiceInfo createFromParcel(Parcel in) {
+ return new OffloadServiceInfo(in);
+ }
+
+ @Override
+ public OffloadServiceInfo[] newArray(int size) {
+ return new OffloadServiceInfo[size];
+ }
+ };
+
+ /**
+ * Get the {@link Key}.
+ */
+ @NonNull
+ public Key getKey() {
+ return mKey;
+ }
+
+ /**
+ * Get the host name. (e.g. "Android.local" )
+ */
+ @NonNull
+ public String getHostname() {
+ return mHostname;
+ }
+
+ /**
+ * Get the service subtypes. (e.g. ["_ann"] )
+ */
+ @NonNull
+ public List<String> getSubtypes() {
+ return Collections.unmodifiableList(mSubtypes);
+ }
+
+ /**
+ * Get the raw udp payload that the OffloadEngine can use to directly reply the incoming query.
+ * <p>
+ * It is null if the OffloadEngine can not handle transmit. The packet must be sent as-is when
+ * replying to query.
+ */
+ @Nullable
+ public byte[] getOffloadPayload() {
+ if (mOffloadPayload == null) {
+ return null;
+ } else {
+ return mOffloadPayload.clone();
+ }
+ }
+
+ /**
+ * Get the offloadType.
+ * <p>
+ * For example, if the {@link com.android.server.NsdService} requests the OffloadEngine to both
+ * filter the mDNS queries and replies, the {@link #mOffloadType} =
+ * ({@link OffloadEngine#OFFLOAD_TYPE_FILTER_QUERIES} |
+ * {@link OffloadEngine#OFFLOAD_TYPE_FILTER_REPLIES}).
+ */
+ @OffloadEngine.OffloadType public long getOffloadType() {
+ return mOffloadType;
+ }
+
+ /**
+ * Get the priority for the OffloadServiceInfo.
+ * <p>
+ * When OffloadEngine don't have enough resource
+ * (e.g. not enough memory) to offload all the OffloadServiceInfo. The OffloadServiceInfo
+ * having lower priority values should be handled by the OffloadEngine first.
+ */
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * Only for debug purpose, the string can be long as the raw packet is dump in the string.
+ */
+ @Override
+ public String toString() {
+ return String.format(
+ "OffloadServiceInfo{ mOffloadServiceInfoKey=%s, mHostName=%s, "
+ + "mOffloadPayload=%s, mPriority=%d, mOffloadType=%d, mSubTypes=%s }",
+ mKey,
+ mHostname, HexDump.dumpHexString(mOffloadPayload), mPriority,
+ mOffloadType, mSubtypes.toString());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof OffloadServiceInfo)) return false;
+ OffloadServiceInfo that = (OffloadServiceInfo) o;
+ return mPriority == that.mPriority && mOffloadType == that.mOffloadType
+ && mKey.equals(that.mKey)
+ && mHostname.equals(
+ that.mHostname) && Arrays.equals(mOffloadPayload,
+ that.mOffloadPayload)
+ && mSubtypes.equals(that.mSubtypes);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mKey, mHostname, mPriority,
+ mOffloadType, mSubtypes);
+ result = 31 * result + Arrays.hashCode(mOffloadPayload);
+ return result;
+ }
+
+ /**
+ * The {@link OffloadServiceInfo.Key} is the (serviceName, serviceType) pair.
+ */
+ public static final class Key implements Parcelable {
+ @NonNull
+ private final String mServiceName;
+ @NonNull
+ private final String mServiceType;
+
+ /**
+ * Creates a new OffloadServiceInfoKey object with the specified parameters.
+ *
+ * @param serviceName The name of the service.
+ * @param serviceType The type of the service.
+ */
+ public Key(@NonNull String serviceName, @NonNull String serviceType) {
+ Objects.requireNonNull(serviceName);
+ Objects.requireNonNull(serviceType);
+ mServiceName = serviceName;
+ mServiceType = serviceType;
+ }
+
+ /**
+ * Creates a new OffloadServiceInfoKey object from a Parcel.
+ *
+ * @param in The Parcel to read the object from.
+ *
+ * @hide
+ */
+ public Key(@NonNull Parcel in) {
+ mServiceName = in.readString();
+ mServiceType = in.readString();
+ }
+ /**
+ * Get the service name. (e.g. "NsdChat")
+ */
+ @NonNull
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ /**
+ * Get the service type. (e.g. "_http._tcp.local" )
+ */
+ @NonNull
+ public String getServiceType() {
+ return mServiceType;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mServiceName);
+ dest.writeString(mServiceType);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<Key> CREATOR =
+ new Creator<Key>() {
+ @Override
+ public Key createFromParcel(Parcel in) {
+ return new Key(in);
+ }
+
+ @Override
+ public Key[] newArray(int size) {
+ return new Key[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Key)) return false;
+ Key that = (Key) o;
+ return Objects.equals(mServiceName, that.mServiceName) && Objects.equals(
+ mServiceType, that.mServiceType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mServiceName, mServiceType);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("OffloadServiceInfoKey{ mServiceName=%s, mServiceType=%s }",
+ mServiceName, mServiceType);
+ }
+ }
+}
diff --git a/framework/aidl-export/android/net/nsd/OffloadServiceInfo.aidl b/framework/aidl-export/android/net/nsd/OffloadServiceInfo.aidl
new file mode 100644
index 0000000..aa7aef2
--- /dev/null
+++ b/framework/aidl-export/android/net/nsd/OffloadServiceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 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.nsd;
+
+@JavaOnlyStableParcelable parcelable OffloadServiceInfo;
\ No newline at end of file
diff --git a/framework/jarjar-excludes.txt b/framework/jarjar-excludes.txt
index 9b48d57..1ac5e8e 100644
--- a/framework/jarjar-excludes.txt
+++ b/framework/jarjar-excludes.txt
@@ -27,4 +27,10 @@
# Don't touch anything that's already under android.net.http (cronet)
# This is required since android.net.http contains api classes and hidden classes.
# TODO: Remove this after hidden classes are moved to different package
-android\.net\.http\..+
\ No newline at end of file
+android\.net\.http\..+
+
+# TODO: OffloadServiceInfo is being added as an API, but wasn't an API yet in the first module
+# versions targeting U. Do not jarjar it such versions so that tests do not have to cover both
+# cases. This will be removed in an upcoming change marking it as API.
+android\.net\.nsd\.OffloadServiceInfo(\$.+)?
+android\.net\.nsd\.OffloadEngine(\$.+)?
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 7de749c..c277cf6 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -88,8 +88,9 @@
name: "service-connectivity-mdns-standalone-build-test",
sdk_version: "core_platform",
srcs: [
- ":service-mdns-droidstubs",
"src/com/android/server/connectivity/mdns/**/*.java",
+ ":framework-connectivity-t-mdns-standalone-build-sources",
+ ":service-mdns-droidstubs"
],
exclude_srcs: [
"src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java",
diff --git a/service-t/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
index dab9d07..8d8dc32 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsService.cpp
@@ -34,6 +34,7 @@
using android::bpf::bpfGetUidStats;
using android::bpf::bpfGetIfaceStats;
+using android::bpf::bpfGetIfIndexStats;
using android::bpf::NetworkTraceHandler;
namespace android {
@@ -94,6 +95,15 @@
}
}
+static jlong nativeGetIfIndexStat(JNIEnv* env, jclass clazz, jint ifindex, jint type) {
+ Stats stats = {};
+ if (bpfGetIfIndexStats(ifindex, &stats) == 0) {
+ return getStatsType(&stats, (StatsType) type);
+ } else {
+ return UNKNOWN;
+ }
+}
+
static jlong nativeGetUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
Stats stats = {};
@@ -111,6 +121,7 @@
static const JNINativeMethod gMethods[] = {
{"nativeGetTotalStat", "(I)J", (void*)nativeGetTotalStat},
{"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)nativeGetIfaceStat},
+ {"nativeGetIfIndexStat", "(II)J", (void*)nativeGetIfIndexStat},
{"nativeGetUidStat", "(II)J", (void*)nativeGetUidStat},
{"nativeInitNetworkTracing", "()V", (void*)nativeInitNetworkTracing},
};
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
index 1bc8ca5..2e6e3e5 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -40,8 +40,19 @@
using base::Result;
+// This explicitly zero-initializes the relevant Stats fields.
+void InitStats(Stats* stats) {
+ stats->rxBytes = 0;
+ stats->rxPackets = 0;
+ stats->txBytes = 0;
+ stats->txPackets = 0;
+ stats->tcpRxPackets = -1;
+ stats->tcpTxPackets = -1;
+}
+
int bpfGetUidStatsInternal(uid_t uid, Stats* stats,
const BpfMap<uint32_t, StatsValue>& appUidStatsMap) {
+ InitStats(stats);
auto statsEntry = appUidStatsMap.readValue(uid);
if (statsEntry.ok()) {
stats->rxPackets = statsEntry.value().rxPackets;
@@ -61,9 +72,8 @@
int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceNameMap) {
+ InitStats(stats);
int64_t unknownIfaceBytesTotal = 0;
- stats->tcpRxPackets = -1;
- stats->tcpTxPackets = -1;
const auto processIfaceStats =
[iface, stats, &ifaceNameMap, &unknownIfaceBytesTotal](
const uint32_t& key,
@@ -95,6 +105,25 @@
return bpfGetIfaceStatsInternal(iface, stats, ifaceStatsMap, ifaceIndexNameMap);
}
+int bpfGetIfIndexStatsInternal(uint32_t ifindex, Stats* stats,
+ const BpfMap<uint32_t, StatsValue>& ifaceStatsMap) {
+ InitStats(stats);
+ auto statsEntry = ifaceStatsMap.readValue(ifindex);
+ if (statsEntry.ok()) {
+ stats->rxPackets = statsEntry.value().rxPackets;
+ stats->txPackets = statsEntry.value().txPackets;
+ stats->rxBytes = statsEntry.value().rxBytes;
+ stats->txBytes = statsEntry.value().txBytes;
+ return 0;
+ }
+ return (statsEntry.error().code() == ENOENT) ? 0 : -statsEntry.error().code();
+}
+
+int bpfGetIfIndexStats(int ifindex, Stats* stats) {
+ static BpfMapRO<uint32_t, StatsValue> ifaceStatsMap(IFACE_STATS_MAP_PATH);
+ return bpfGetIfIndexStatsInternal(ifindex, stats, ifaceStatsMap);
+}
+
stats_line populateStatsEntry(const StatsKey& statsKey, const StatsValue& statsEntry,
const char* ifname) {
stats_line newLine;
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
index ccd3f5e..4f85d9b 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
@@ -275,6 +275,20 @@
expectStatsEqual(totalValue, totalResult);
}
+TEST_F(BpfNetworkStatsHelperTest, TestGetIfIndexStatsInternal) {
+ StatsValue value = {
+ .rxPackets = TEST_PACKET0,
+ .rxBytes = TEST_BYTES0,
+ .txPackets = TEST_PACKET1,
+ .txBytes = TEST_BYTES1,
+ };
+ EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(IFACE_INDEX1, value, BPF_ANY));
+
+ Stats result = {};
+ ASSERT_EQ(0, bpfGetIfIndexStatsInternal(IFACE_INDEX1, &result, mFakeIfaceStatsMap));
+ expectStatsEqual(value, result);
+}
+
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
index 133009f..0a9c012 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
@@ -63,6 +63,9 @@
const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceNameMap);
// For test only
+int bpfGetIfIndexStatsInternal(uint32_t ifindex, Stats* stats,
+ const BpfMap<uint32_t, StatsValue>& ifaceStatsMap);
+// For test only
int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
const BpfMap<StatsKey, StatsValue>& statsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceMap);
@@ -112,6 +115,7 @@
int bpfGetUidStats(uid_t uid, Stats* stats);
int bpfGetIfaceStats(const char* iface, Stats* stats);
+int bpfGetIfIndexStats(int ifindex, Stats* stats);
int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines);
int parseBpfNetworkStatsDev(std::vector<stats_line>* lines);
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 745c5bc..53782ac 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -46,9 +47,12 @@
import android.net.nsd.INsdManager;
import android.net.nsd.INsdManagerCallback;
import android.net.nsd.INsdServiceConnector;
+import android.net.nsd.IOffloadEngine;
import android.net.nsd.MDnsManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
+import android.net.nsd.OffloadEngine;
+import android.net.nsd.OffloadServiceInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Handler;
@@ -56,6 +60,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -98,6 +103,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -215,6 +221,24 @@
// The number of client that ever connected.
private int mClientNumberId = 1;
+ private final RemoteCallbackList<IOffloadEngine> mOffloadEngines =
+ new RemoteCallbackList<>();
+
+ private static class OffloadEngineInfo {
+ @NonNull final String mInterfaceName;
+ final long mOffloadCapabilities;
+ final long mOffloadType;
+ @NonNull final IOffloadEngine mOffloadEngine;
+
+ OffloadEngineInfo(@NonNull IOffloadEngine offloadEngine,
+ @NonNull String interfaceName, long capabilities, long offloadType) {
+ this.mOffloadEngine = offloadEngine;
+ this.mInterfaceName = interfaceName;
+ this.mOffloadCapabilities = capabilities;
+ this.mOffloadType = offloadType;
+ }
+ }
+
private static class MdnsListener implements MdnsServiceBrowserListener {
protected final int mClientRequestId;
protected final int mTransactionId;
@@ -719,6 +743,7 @@
final int transactionId;
final int clientRequestId = msg.arg2;
final ListenerArgs args;
+ final OffloadEngineInfo offloadEngineInfo;
switch (msg.what) {
case NsdManager.DISCOVER_SERVICES: {
if (DBG) Log.d(TAG, "Discover services");
@@ -1114,6 +1139,16 @@
return NOT_HANDLED;
}
break;
+ case NsdManager.REGISTER_OFFLOAD_ENGINE:
+ offloadEngineInfo = (OffloadEngineInfo) msg.obj;
+ // TODO: Limits the number of registrations created by a given class.
+ mOffloadEngines.register(offloadEngineInfo.mOffloadEngine,
+ offloadEngineInfo);
+ // TODO: Sends all the existing OffloadServiceInfos back.
+ break;
+ case NsdManager.UNREGISTER_OFFLOAD_ENGINE:
+ mOffloadEngines.unregister((IOffloadEngine) msg.obj);
+ break;
default:
return NOT_HANDLED;
}
@@ -1573,7 +1608,8 @@
mRunningAppActiveImportanceCutoff);
mMdnsSocketClient =
- new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
+ new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider,
+ LOGGER.forSubComponent("MdnsMultinetworkSocketClient"));
mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"));
handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
@@ -1771,7 +1807,42 @@
}
}
+ private void sendOffloadServiceInfosUpdate(@NonNull String targetInterfaceName,
+ @NonNull OffloadServiceInfo offloadServiceInfo, boolean isRemove) {
+ final int count = mOffloadEngines.beginBroadcast();
+ try {
+ for (int i = 0; i < count; i++) {
+ final OffloadEngineInfo offloadEngineInfo =
+ (OffloadEngineInfo) mOffloadEngines.getBroadcastCookie(i);
+ final String interfaceName = offloadEngineInfo.mInterfaceName;
+ if (!targetInterfaceName.equals(interfaceName)
+ || ((offloadEngineInfo.mOffloadType
+ & offloadServiceInfo.getOffloadType()) == 0)) {
+ continue;
+ }
+ try {
+ if (isRemove) {
+ mOffloadEngines.getBroadcastItem(i).onOffloadServiceRemoved(
+ offloadServiceInfo);
+ } else {
+ mOffloadEngines.getBroadcastItem(i).onOffloadServiceUpdated(
+ offloadServiceInfo);
+ }
+ } catch (RemoteException e) {
+ // Can happen in regular cases, do not log a stacktrace
+ Log.i(TAG, "Failed to send offload callback, remote died", e);
+ }
+ }
+ } finally {
+ mOffloadEngines.finishBroadcast();
+ }
+ }
+
private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback {
+ // TODO: add a callback to notify when a service is being added on each interface (as soon
+ // as probing starts), and call mOffloadCallbacks. This callback is for
+ // OFFLOAD_CAPABILITY_FILTER_REPLIES offload type.
+
@Override
public void onRegisterServiceSucceeded(int transactionId, NsdServiceInfo registeredInfo) {
mServiceLogs.log("onRegisterServiceSucceeded: transactionId " + transactionId);
@@ -1801,6 +1872,18 @@
request.calculateRequestDurationMs());
}
+ @Override
+ public void onOffloadStartOrUpdate(@NonNull String interfaceName,
+ @NonNull OffloadServiceInfo offloadServiceInfo) {
+ sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, false /* isRemove */);
+ }
+
+ @Override
+ public void onOffloadStop(@NonNull String interfaceName,
+ @NonNull OffloadServiceInfo offloadServiceInfo) {
+ sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, true /* isRemove */);
+ }
+
private ClientInfo getClientInfoOrLog(int transactionId) {
final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
if (clientInfo == null) {
@@ -1920,6 +2003,32 @@
public void binderDied() {
mNsdStateMachine.sendMessage(
mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
+
+ }
+
+ @Override
+ public void registerOffloadEngine(String ifaceName, IOffloadEngine cb,
+ @OffloadEngine.OffloadCapability long offloadCapabilities,
+ @OffloadEngine.OffloadType long offloadTypes) {
+ // TODO: Relax the permission because NETWORK_SETTINGS is a signature permission, and
+ // it may not be possible for all the callers of this API to have it.
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS);
+ Objects.requireNonNull(ifaceName);
+ Objects.requireNonNull(cb);
+ mNsdStateMachine.sendMessage(
+ mNsdStateMachine.obtainMessage(NsdManager.REGISTER_OFFLOAD_ENGINE,
+ new OffloadEngineInfo(cb, ifaceName, offloadCapabilities,
+ offloadTypes)));
+ }
+
+ @Override
+ public void unregisterOffloadEngine(IOffloadEngine cb) {
+ // TODO: Relax the permission because NETWORK_SETTINGS is a signature permission, and
+ // it may not be possible for all the callers of this API to have it.
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS);
+ Objects.requireNonNull(cb);
+ mNsdStateMachine.sendMessage(
+ mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_OFFLOAD_ENGINE, cb));
}
}
@@ -2003,25 +2112,41 @@
return IFACE_IDX_ANY;
}
- final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
- if (cm == null) {
- Log.wtf(TAG, "No ConnectivityManager for resolveService");
+ String interfaceName = getNetworkInterfaceName(network);
+ if (interfaceName == null) {
return IFACE_IDX_ANY;
}
- final LinkProperties lp = cm.getLinkProperties(network);
- if (lp == null) return IFACE_IDX_ANY;
+ return getNetworkInterfaceIndexByName(interfaceName);
+ }
+ private String getNetworkInterfaceName(@Nullable Network network) {
+ if (network == null) {
+ return null;
+ }
+ final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ if (cm == null) {
+ Log.wtf(TAG, "No ConnectivityManager");
+ return null;
+ }
+ final LinkProperties lp = cm.getLinkProperties(network);
+ if (lp == null) {
+ return null;
+ }
// Only resolve on non-stacked interfaces
+ return lp.getInterfaceName();
+ }
+
+ private int getNetworkInterfaceIndexByName(final String ifaceName) {
final NetworkInterface iface;
try {
- iface = NetworkInterface.getByName(lp.getInterfaceName());
+ iface = NetworkInterface.getByName(ifaceName);
} catch (SocketException e) {
Log.e(TAG, "Error querying interface", e);
return IFACE_IDX_ANY;
}
if (iface == null) {
- Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
+ Log.e(TAG, "Interface not found: " + ifaceName);
return IFACE_IDX_ANY;
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java b/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java
index 551e3db..87aa0d2 100644
--- a/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManager.java
@@ -25,13 +25,12 @@
import android.net.NetworkRequest;
import android.os.Build;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
/** Class for monitoring connectivity changes using {@link ConnectivityManager}. */
public class ConnectivityMonitorWithConnectivityManager implements ConnectivityMonitor {
private static final String TAG = "ConnMntrWConnMgr";
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
-
+ private final SharedLog sharedLog;
private final Listener listener;
private final ConnectivityManager.NetworkCallback networkCallback;
private final ConnectivityManager connectivityManager;
@@ -42,8 +41,10 @@
@SuppressWarnings({"nullness:assignment", "nullness:method.invocation"})
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public ConnectivityMonitorWithConnectivityManager(Context context, Listener listener) {
+ public ConnectivityMonitorWithConnectivityManager(Context context, Listener listener,
+ SharedLog sharedLog) {
this.listener = listener;
+ this.sharedLog = sharedLog;
connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -51,20 +52,20 @@
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
- LOGGER.log("network available.");
+ sharedLog.log("network available.");
lastAvailableNetwork = network;
notifyConnectivityChange();
}
@Override
public void onLost(Network network) {
- LOGGER.log("network lost.");
+ sharedLog.log("network lost.");
notifyConnectivityChange();
}
@Override
public void onUnavailable() {
- LOGGER.log("network unavailable.");
+ sharedLog.log("network unavailable.");
notifyConnectivityChange();
}
};
@@ -82,7 +83,7 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void startWatchingConnectivityChanges() {
- LOGGER.log("Start watching connectivity changes");
+ sharedLog.log("Start watching connectivity changes");
if (isCallbackRegistered) {
return;
}
@@ -98,7 +99,7 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void stopWatchingConnectivityChanges() {
- LOGGER.log("Stop watching connectivity changes");
+ sharedLog.log("Stop watching connectivity changes");
if (!isCallbackRegistered) {
return;
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
index b7417ed..fa3b646 100644
--- a/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
+++ b/service-t/src/com/android/server/connectivity/mdns/EnqueueMdnsQueryCallable.java
@@ -20,10 +20,9 @@
import android.annotation.NonNull;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Pair;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.util.MdnsUtils;
import java.io.IOException;
@@ -44,7 +43,6 @@
public class EnqueueMdnsQueryCallable implements Callable<Pair<Integer, List<String>>> {
private static final String TAG = "MdnsQueryCallable";
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
private static final List<Integer> castShellEmulatorMdnsPorts;
static {
@@ -77,6 +75,8 @@
private final List<MdnsResponse> servicesToResolve;
@NonNull
private final MdnsUtils.Clock clock;
+ @NonNull
+ private final SharedLog sharedLog;
private final boolean onlyUseIpv6OnIpv6OnlyNetworks;
EnqueueMdnsQueryCallable(
@@ -90,7 +90,8 @@
boolean onlyUseIpv6OnIpv6OnlyNetworks,
boolean sendDiscoveryQueries,
@NonNull Collection<MdnsResponse> servicesToResolve,
- @NonNull MdnsUtils.Clock clock) {
+ @NonNull MdnsUtils.Clock clock,
+ @NonNull SharedLog sharedLog) {
weakRequestSender = new WeakReference<>(requestSender);
this.packetWriter = packetWriter;
serviceTypeLabels = TextUtils.split(serviceType, "\\.");
@@ -102,6 +103,7 @@
this.sendDiscoveryQueries = sendDiscoveryQueries;
this.servicesToResolve = new ArrayList<>(servicesToResolve);
this.clock = clock;
+ this.sharedLog = sharedLog;
}
/**
@@ -200,7 +202,7 @@
}
return Pair.create(transactionId, subtypes);
} catch (IOException e) {
- LOGGER.e(String.format("Failed to create mDNS packet for subtype: %s.",
+ sharedLog.e(String.format("Failed to create mDNS packet for subtype: %s.",
TextUtils.join(",", subtypes)), e);
return Pair.create(INVALID_TRANSACTION_ID, new ArrayList<>());
}
@@ -242,13 +244,13 @@
sendPacket(requestSender,
new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), port));
} catch (IOException e) {
- Log.i(TAG, "Can't send packet to IPv4", e);
+ sharedLog.e("Can't send packet to IPv4", e);
}
try {
sendPacket(requestSender,
new InetSocketAddress(MdnsConstants.getMdnsIPv6Address(), port));
} catch (IOException e) {
- Log.i(TAG, "Can't send packet to IPv6", e);
+ sharedLog.e("Can't send packet to IPv6", e);
}
}
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
index 158d7a3..dd72d11 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -24,15 +24,19 @@
import android.net.Network;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
+import android.net.nsd.OffloadEngine;
+import android.net.nsd.OffloadServiceInfo;
import android.os.Looper;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.util.MdnsUtils;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -68,9 +72,10 @@
new ArrayMap<>();
private final SparseArray<Registration> mRegistrations = new SparseArray<>();
private final Dependencies mDeps;
-
private String[] mDeviceHostName;
@NonNull private final SharedLog mSharedLog;
+ private final Map<String, List<OffloadServiceInfoWrapper>> mInterfaceOffloadServices =
+ new ArrayMap<>();
/**
* Dependencies for {@link MdnsAdvertiser}, useful for testing.
@@ -115,18 +120,32 @@
private final MdnsInterfaceAdvertiser.Callback mInterfaceAdvertiserCb =
new MdnsInterfaceAdvertiser.Callback() {
@Override
- public void onRegisterServiceSucceeded(
+ public void onServiceProbingSucceeded(
@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId) {
+ final Registration registration = mRegistrations.get(serviceId);
+ if (registration == null) {
+ mSharedLog.wtf("Register succeeded for unknown registration");
+ return;
+ }
+
+ final String interfaceName = advertiser.getSocketInterfaceName();
+ final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
+ mInterfaceOffloadServices.computeIfAbsent(
+ interfaceName, k -> new ArrayList<>());
+ // Remove existing offload services from cache for update.
+ existingOffloadServiceInfoWrappers.removeIf(item -> item.mServiceId == serviceId);
+ final OffloadServiceInfoWrapper newOffloadServiceInfoWrapper = createOffloadService(
+ serviceId,
+ registration);
+ existingOffloadServiceInfoWrappers.add(newOffloadServiceInfoWrapper);
+ mCb.onOffloadStartOrUpdate(interfaceName,
+ newOffloadServiceInfoWrapper.mOffloadServiceInfo);
+
// Wait for all current interfaces to be done probing before notifying of success.
if (any(mAllAdvertisers, (k, a) -> a.isProbing(serviceId))) return;
// The service may still be unregistered/renamed if a conflict is found on a later added
// interface, or if a conflicting announcement/reply is detected (RFC6762 9.)
- final Registration registration = mRegistrations.get(serviceId);
- if (registration == null) {
- Log.wtf(TAG, "Register succeeded for unknown registration");
- return;
- }
if (!registration.mNotifiedRegistrationSuccess) {
mCb.onRegisterServiceSucceeded(serviceId, registration.getServiceInfo());
registration.mNotifiedRegistrationSuccess = true;
@@ -148,7 +167,12 @@
registration.mNotifiedRegistrationSuccess = false;
// The service was done probing, just reset it to probing state (RFC6762 9.)
- forAllAdvertisers(a -> a.restartProbingForConflict(serviceId));
+ forAllAdvertisers(a -> {
+ if (!a.maybeRestartProbingForConflict(serviceId)) {
+ return;
+ }
+ maybeSendOffloadStop(a.getSocketInterfaceName(), serviceId);
+ });
return;
}
@@ -196,6 +220,22 @@
registration.updateForConflict(newInfo, renameCount);
}
+ private void maybeSendOffloadStop(final String interfaceName, int serviceId) {
+ final List<OffloadServiceInfoWrapper> existingOffloadServiceInfoWrappers =
+ mInterfaceOffloadServices.get(interfaceName);
+ if (existingOffloadServiceInfoWrappers == null) {
+ return;
+ }
+ // Stop the offloaded service by matching the service id
+ int idx = CollectionUtils.indexOf(existingOffloadServiceInfoWrappers,
+ item -> item.mServiceId == serviceId);
+ if (idx >= 0) {
+ mCb.onOffloadStop(interfaceName,
+ existingOffloadServiceInfoWrappers.get(idx).mOffloadServiceInfo);
+ existingOffloadServiceInfoWrappers.remove(idx);
+ }
+ }
+
/**
* A request for a {@link MdnsInterfaceAdvertiser}.
*
@@ -221,7 +261,22 @@
* @return true if this {@link InterfaceAdvertiserRequest} should now be deleted.
*/
boolean onAdvertiserDestroyed(@NonNull MdnsInterfaceSocket socket) {
- mAdvertisers.remove(socket);
+ final MdnsInterfaceAdvertiser removedAdvertiser = mAdvertisers.remove(socket);
+ if (removedAdvertiser != null) {
+ final String interfaceName = removedAdvertiser.getSocketInterfaceName();
+ // If the interface is destroyed, stop all hardware offloading on that interface.
+ final List<OffloadServiceInfoWrapper> offloadServiceInfoWrappers =
+ mInterfaceOffloadServices.remove(
+ interfaceName);
+ if (offloadServiceInfoWrappers != null) {
+ for (OffloadServiceInfoWrapper offloadServiceInfoWrapper :
+ offloadServiceInfoWrappers) {
+ mCb.onOffloadStop(interfaceName,
+ offloadServiceInfoWrapper.mOffloadServiceInfo);
+ }
+ }
+ }
+
if (mAdvertisers.size() == 0 && mPendingRegistrations.size() == 0) {
// No advertiser is using sockets from this request anymore (in particular for exit
// announcements), and there is no registration so newer sockets will not be
@@ -274,7 +329,8 @@
mAdvertisers.valueAt(i).addService(
id, registration.getServiceInfo(), registration.getSubtype());
} catch (NameConflictException e) {
- Log.wtf(TAG, "Name conflict adding services that should have unique names", e);
+ mSharedLog.wtf("Name conflict adding services that should have unique names",
+ e);
}
}
}
@@ -282,7 +338,10 @@
void removeService(int id) {
mPendingRegistrations.remove(id);
for (int i = 0; i < mAdvertisers.size(); i++) {
- mAdvertisers.valueAt(i).removeService(id);
+ final MdnsInterfaceAdvertiser advertiser = mAdvertisers.valueAt(i);
+ advertiser.removeService(id);
+
+ maybeSendOffloadStop(advertiser.getSocketInterfaceName(), id);
}
}
@@ -305,7 +364,8 @@
advertiser.addService(mPendingRegistrations.keyAt(i),
registration.getServiceInfo(), registration.getSubtype());
} catch (NameConflictException e) {
- Log.wtf(TAG, "Name conflict adding services that should have unique names", e);
+ mSharedLog.wtf("Name conflict adding services that should have unique names",
+ e);
}
}
}
@@ -325,6 +385,16 @@
}
}
+ private static class OffloadServiceInfoWrapper {
+ private final @NonNull OffloadServiceInfo mOffloadServiceInfo;
+ private final int mServiceId;
+
+ OffloadServiceInfoWrapper(int serviceId, OffloadServiceInfo offloadServiceInfo) {
+ mOffloadServiceInfo = offloadServiceInfo;
+ mServiceId = serviceId;
+ }
+ }
+
private static class Registration {
@NonNull
final String mOriginalName;
@@ -425,6 +495,24 @@
// Unregistration is notified immediately as success in NsdService so no callback is needed
// here.
+
+ /**
+ * Called when a service is ready to be sent for hardware offloading.
+ *
+ * @param interfaceName the interface for sending the update to.
+ * @param offloadServiceInfo the offloading content.
+ */
+ void onOffloadStartOrUpdate(@NonNull String interfaceName,
+ @NonNull OffloadServiceInfo offloadServiceInfo);
+
+ /**
+ * Called when a service is removed or the MdnsInterfaceAdvertiser is destroyed.
+ *
+ * @param interfaceName the interface for sending the update to.
+ * @param offloadServiceInfo the offloading content.
+ */
+ void onOffloadStop(@NonNull String interfaceName,
+ @NonNull OffloadServiceInfo offloadServiceInfo);
}
public MdnsAdvertiser(@NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
@@ -459,7 +547,7 @@
public void addService(int id, NsdServiceInfo service, @Nullable String subtype) {
checkThread();
if (mRegistrations.get(id) != null) {
- Log.e(TAG, "Adding duplicate registration for " + service);
+ mSharedLog.e("Adding duplicate registration for " + service);
// TODO (b/264986328): add a more specific error code
mCb.onRegisterServiceFailed(id, NsdManager.FAILURE_INTERNAL_ERROR);
return;
@@ -525,4 +613,28 @@
return false;
});
}
+
+ private OffloadServiceInfoWrapper createOffloadService(int serviceId,
+ @NonNull Registration registration) {
+ final NsdServiceInfo nsdServiceInfo = registration.getServiceInfo();
+ List<String> subTypes = new ArrayList<>();
+ String subType = registration.getSubtype();
+ if (subType != null) {
+ subTypes.add(subType);
+ }
+ final OffloadServiceInfo offloadServiceInfo = new OffloadServiceInfo(
+ new OffloadServiceInfo.Key(nsdServiceInfo.getServiceName(),
+ nsdServiceInfo.getServiceType()),
+ subTypes,
+ String.join(".", mDeviceHostName),
+ null /* rawOffloadPacket */,
+ // TODO: define overlayable resources in
+ // ServiceConnectivityResources that set the priority based on
+ // service type.
+ 0 /* priority */,
+ // TODO: set the offloadType based on the callback timing.
+ OffloadEngine.OFFLOAD_TYPE_REPLY);
+ return new OffloadServiceInfoWrapper(serviceId, offloadServiceInfo);
+ }
+
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
index 27fc945..fd2c32e 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAnnouncer.java
@@ -21,6 +21,7 @@
import android.os.Looper;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.SharedLog;
import java.util.Collections;
import java.util.List;
@@ -39,9 +40,6 @@
private static final long EXIT_DELAY_MS = 2000L;
private static final int EXIT_COUNT = 3;
- @NonNull
- private final String mLogTag;
-
/** Base class for announcement requests to send with {@link MdnsAnnouncer}. */
public abstract static class BaseAnnouncementInfo implements MdnsPacketRepeater.Request {
private final int mServiceId;
@@ -105,16 +103,11 @@
}
}
- public MdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper,
+ public MdnsAnnouncer(@NonNull Looper looper,
@NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb) {
- super(looper, replySender, cb);
- mLogTag = MdnsAnnouncer.class.getSimpleName() + "/" + interfaceTag;
- }
-
- @Override
- protected String getTag() {
- return mLogTag;
+ @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb,
+ @NonNull SharedLog sharedLog) {
+ super(looper, replySender, cb, sharedLog);
}
// TODO: Notify MdnsRecordRepository that the records were announced for that service ID,
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
index 724a704..a83b852 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
@@ -22,7 +22,6 @@
import android.net.nsd.NsdServiceInfo;
import android.os.Handler;
import android.os.Looper;
-import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.HexDump;
@@ -42,8 +41,6 @@
@VisibleForTesting
public static final long EXIT_ANNOUNCEMENT_DELAY_MS = 100L;
@NonNull
- private final String mTag;
- @NonNull
private final ProbingCallback mProbingCallback = new ProbingCallback();
@NonNull
private final AnnouncingCallback mAnnouncingCallback = new AnnouncingCallback();
@@ -73,7 +70,7 @@
/**
* Called by the advertiser after it successfully registered a service, after probing.
*/
- void onRegisterServiceSucceeded(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId);
+ void onServiceProbingSucceeded(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId);
/**
* Called by the advertiser when a conflict was found, during or after probing.
@@ -101,7 +98,7 @@
public void onFinished(MdnsProber.ProbingInfo info) {
final MdnsAnnouncer.AnnouncementInfo announcementInfo;
mSharedLog.i("Probing finished for service " + info.getServiceId());
- mCbHandler.post(() -> mCb.onRegisterServiceSucceeded(
+ mCbHandler.post(() -> mCb.onServiceProbingSucceeded(
MdnsInterfaceAdvertiser.this, info.getServiceId()));
try {
announcementInfo = mRecordRepository.onProbingSucceeded(info);
@@ -151,22 +148,30 @@
/** @see MdnsReplySender */
@NonNull
public MdnsReplySender makeReplySender(@NonNull String interfaceTag, @NonNull Looper looper,
- @NonNull MdnsInterfaceSocket socket, @NonNull byte[] packetCreationBuffer) {
- return new MdnsReplySender(interfaceTag, looper, socket, packetCreationBuffer);
+ @NonNull MdnsInterfaceSocket socket, @NonNull byte[] packetCreationBuffer,
+ @NonNull SharedLog sharedLog) {
+ return new MdnsReplySender(looper, socket, packetCreationBuffer,
+ sharedLog.forSubComponent(
+ MdnsReplySender.class.getSimpleName() + "/" + interfaceTag));
}
/** @see MdnsAnnouncer */
public MdnsAnnouncer makeMdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper,
@NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<MdnsAnnouncer.BaseAnnouncementInfo> cb) {
- return new MdnsAnnouncer(interfaceTag, looper, replySender, cb);
+ @Nullable PacketRepeaterCallback<MdnsAnnouncer.BaseAnnouncementInfo> cb,
+ @NonNull SharedLog sharedLog) {
+ return new MdnsAnnouncer(looper, replySender, cb,
+ sharedLog.forSubComponent(
+ MdnsAnnouncer.class.getSimpleName() + "/" + interfaceTag));
}
/** @see MdnsProber */
public MdnsProber makeMdnsProber(@NonNull String interfaceTag, @NonNull Looper looper,
@NonNull MdnsReplySender replySender,
- @NonNull PacketRepeaterCallback<MdnsProber.ProbingInfo> cb) {
- return new MdnsProber(interfaceTag, looper, replySender, cb);
+ @NonNull PacketRepeaterCallback<MdnsProber.ProbingInfo> cb,
+ @NonNull SharedLog sharedLog) {
+ return new MdnsProber(looper, replySender, cb, sharedLog.forSubComponent(
+ MdnsProber.class.getSimpleName() + "/" + interfaceTag));
}
}
@@ -182,17 +187,17 @@
@NonNull List<LinkAddress> initialAddresses, @NonNull Looper looper,
@NonNull byte[] packetCreationBuffer, @NonNull Callback cb, @NonNull Dependencies deps,
@NonNull String[] deviceHostName, @NonNull SharedLog sharedLog) {
- mTag = MdnsInterfaceAdvertiser.class.getSimpleName() + "/" + sharedLog.getTag();
mRecordRepository = deps.makeRecordRepository(looper, deviceHostName);
mRecordRepository.updateAddresses(initialAddresses);
mSocket = socket;
mCb = cb;
mCbHandler = new Handler(looper);
mReplySender = deps.makeReplySender(sharedLog.getTag(), looper, socket,
- packetCreationBuffer);
+ packetCreationBuffer, sharedLog);
mAnnouncer = deps.makeMdnsAnnouncer(sharedLog.getTag(), looper, mReplySender,
- mAnnouncingCallback);
- mProber = deps.makeMdnsProber(sharedLog.getTag(), looper, mReplySender, mProbingCallback);
+ mAnnouncingCallback, sharedLog);
+ mProber = deps.makeMdnsProber(sharedLog.getTag(), looper, mReplySender, mProbingCallback,
+ sharedLog);
mSharedLog = sharedLog;
}
@@ -282,11 +287,12 @@
/**
* Reset a service to the probing state due to a conflict found on the network.
*/
- public void restartProbingForConflict(int serviceId) {
+ public boolean maybeRestartProbingForConflict(int serviceId) {
final MdnsProber.ProbingInfo probingInfo = mRecordRepository.setServiceProbing(serviceId);
- if (probingInfo == null) return;
+ if (probingInfo == null) return false;
mProber.restartForConflict(probingInfo);
+ return true;
}
/**
@@ -317,20 +323,18 @@
try {
packet = MdnsPacket.parse(new MdnsPacketReader(recvbuf, length));
} catch (MdnsPacket.ParseException e) {
- Log.e(mTag, "Error parsing mDNS packet", e);
+ mSharedLog.e("Error parsing mDNS packet", e);
if (DBG) {
- Log.v(
- mTag, "Packet: " + HexDump.toHexString(recvbuf, 0, length));
+ mSharedLog.v("Packet: " + HexDump.toHexString(recvbuf, 0, length));
}
return;
}
if (DBG) {
- Log.v(mTag,
- "Parsed packet with " + packet.questions.size() + " questions, "
- + packet.answers.size() + " answers, "
- + packet.authorityRecords.size() + " authority, "
- + packet.additionalRecords.size() + " additional from " + src);
+ mSharedLog.v("Parsed packet with " + packet.questions.size() + " questions, "
+ + packet.answers.size() + " answers, "
+ + packet.authorityRecords.size() + " authority, "
+ + packet.additionalRecords.size() + " additional from " + src);
}
for (int conflictServiceId : mRecordRepository.getConflictingServices(packet)) {
@@ -346,4 +350,8 @@
if (answers == null) return;
mReplySender.queueReply(answers);
}
+
+ public String getSocketInterfaceName() {
+ return mSocket.getInterface().getName();
+ }
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java
index 119c7a8..534f8d0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceSocket.java
@@ -28,7 +28,8 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
-import android.util.Log;
+
+import com.android.net.module.util.SharedLog;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -54,11 +55,12 @@
@NonNull private final NetworkInterface mNetworkInterface;
@NonNull private final MulticastPacketReader mPacketReader;
@NonNull private final ParcelFileDescriptor mFileDescriptor;
+ @NonNull private final SharedLog mSharedLog;
private boolean mJoinedIpv4 = false;
private boolean mJoinedIpv6 = false;
public MdnsInterfaceSocket(@NonNull NetworkInterface networkInterface, int port,
- @NonNull Looper looper, @NonNull byte[] packetReadBuffer)
+ @NonNull Looper looper, @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog)
throws IOException {
mNetworkInterface = networkInterface;
mMulticastSocket = new MulticastSocket(port);
@@ -80,6 +82,8 @@
mPacketReader = new MulticastPacketReader(networkInterface.getName(), mFileDescriptor,
new Handler(looper), packetReadBuffer);
mPacketReader.start();
+
+ mSharedLog = sharedLog;
}
/**
@@ -117,7 +121,7 @@
return true;
} catch (IOException e) {
// The address may have just been removed
- Log.e(TAG, "Error joining multicast group for " + mNetworkInterface, e);
+ mSharedLog.e("Error joining multicast group for " + mNetworkInterface, e);
return false;
}
}
@@ -148,7 +152,7 @@
try {
mFileDescriptor.close();
} catch (IOException e) {
- Log.e(TAG, "Close file descriptor failed.");
+ mSharedLog.e("Close file descriptor failed.");
}
mMulticastSocket.close();
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index d1fa57c..097dbe0 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -25,7 +25,8 @@
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
-import android.util.Log;
+
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -46,6 +47,7 @@
@NonNull private final Handler mHandler;
@NonNull private final MdnsSocketProvider mSocketProvider;
+ @NonNull private final SharedLog mSharedLog;
private final ArrayMap<MdnsServiceBrowserListener, InterfaceSocketCallback> mRequestedNetworks =
new ArrayMap<>();
@@ -55,9 +57,11 @@
private int mReceivedPacketNumber = 0;
public MdnsMultinetworkSocketClient(@NonNull Looper looper,
- @NonNull MdnsSocketProvider provider) {
+ @NonNull MdnsSocketProvider provider,
+ @NonNull SharedLog sharedLog) {
mHandler = new Handler(looper);
mSocketProvider = provider;
+ mSharedLog = sharedLog;
}
private class InterfaceSocketCallback implements MdnsSocketProvider.SocketCallback {
@@ -172,7 +176,7 @@
throw new IllegalArgumentException("Can not register duplicated listener");
}
- if (DBG) Log.d(TAG, "notifyNetworkRequested: network=" + network);
+ if (DBG) mSharedLog.v("notifyNetworkRequested: network=" + network);
callback = new InterfaceSocketCallback(socketCreationCallback);
mRequestedNetworks.put(listener, callback);
mSocketProvider.requestSocket(network, callback);
@@ -184,7 +188,7 @@
ensureRunningOnHandlerThread(mHandler);
final InterfaceSocketCallback callback = mRequestedNetworks.get(listener);
if (callback == null) {
- Log.e(TAG, "Can not be unrequested with unknown listener=" + listener);
+ mSharedLog.e("Can not be unrequested with unknown listener=" + listener);
return;
}
callback.onNetworkUnrequested();
@@ -222,7 +226,7 @@
try {
socket.send(packet);
} catch (IOException e) {
- Log.e(TAG, "Failed to send a mDNS packet.", e);
+ mSharedLog.e("Failed to send a mDNS packet.", e);
}
}
}
@@ -249,7 +253,7 @@
response = MdnsResponseDecoder.parseResponse(recvbuf, length);
} catch (MdnsPacket.ParseException e) {
if (e.code != MdnsResponseErrorCode.ERROR_NOT_RESPONSE_MESSAGE) {
- Log.e(TAG, e.getMessage(), e);
+ mSharedLog.e(e.getMessage(), e);
if (mCallback != null) {
mCallback.onFailedToParseMdnsResponse(packetNumber, e.code, socketKey);
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
index 4c385da..644560c 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsPacketRepeater.java
@@ -24,7 +24,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.Log;
+
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -45,6 +46,8 @@
protected final Handler mHandler;
@Nullable
private final PacketRepeaterCallback<T> mCb;
+ @NonNull
+ private final SharedLog mSharedLog;
/**
* Status callback from {@link MdnsPacketRepeater}.
@@ -87,12 +90,6 @@
int getNumSends();
}
- /**
- * Get the logging tag to use.
- */
- @NonNull
- protected abstract String getTag();
-
private final class ProbeHandler extends Handler {
ProbeHandler(@NonNull Looper looper) {
super(looper);
@@ -112,7 +109,7 @@
final MdnsPacket packet = request.getPacket(index);
if (DBG) {
- Log.v(getTag(), "Sending packets for iteration " + index + " out of "
+ mSharedLog.v("Sending packets for iteration " + index + " out of "
+ request.getNumSends() + " for ID " + msg.what);
}
// Send to both v4 and v6 addresses; the reply sender will take care of ignoring the
@@ -121,7 +118,7 @@
try {
mReplySender.sendNow(packet, destination);
} catch (IOException e) {
- Log.e(getTag(), "Error sending packet to " + destination, e);
+ mSharedLog.e("Error sending packet to " + destination, e);
}
}
@@ -133,7 +130,7 @@
// likely not to be available since the device is in deep sleep anyway.
final long delay = request.getDelayMs(nextIndex);
sendMessageDelayed(obtainMessage(msg.what, nextIndex, 0, request), delay);
- if (DBG) Log.v(getTag(), "Scheduled next packet in " + delay + "ms");
+ if (DBG) mSharedLog.v("Scheduled next packet in " + delay + "ms");
}
// Call onSent after scheduling the next run, to allow the callback to cancel it
@@ -144,15 +141,16 @@
}
protected MdnsPacketRepeater(@NonNull Looper looper, @NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<T> cb) {
+ @Nullable PacketRepeaterCallback<T> cb, @NonNull SharedLog sharedLog) {
mHandler = new ProbeHandler(looper);
mReplySender = replySender;
mCb = cb;
+ mSharedLog = sharedLog;
}
protected void startSending(int id, @NonNull T request, long initialDelayMs) {
if (DBG) {
- Log.v(getTag(), "Starting send with id " + id + ", request "
+ mSharedLog.v("Starting send with id " + id + ", request "
+ request.getClass().getSimpleName() + ", delay " + initialDelayMs);
}
mHandler.sendMessageDelayed(mHandler.obtainMessage(id, 0, 0, request), initialDelayMs);
@@ -171,7 +169,7 @@
// message cannot be cancelled.
if (mHandler.hasMessages(id)) {
if (DBG) {
- Log.v(getTag(), "Stopping send on id " + id);
+ mSharedLog.v("Stopping send on id " + id);
}
mHandler.removeMessages(id);
return true;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
index ecf846e..ba37f32 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsProber.java
@@ -21,6 +21,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.util.MdnsUtils;
import java.util.ArrayList;
@@ -34,14 +35,11 @@
*/
public class MdnsProber extends MdnsPacketRepeater<MdnsProber.ProbingInfo> {
private static final long CONFLICT_RETRY_DELAY_MS = 5_000L;
- @NonNull
- private final String mLogTag;
- public MdnsProber(@NonNull String interfaceTag, @NonNull Looper looper,
- @NonNull MdnsReplySender replySender,
- @NonNull PacketRepeaterCallback<ProbingInfo> cb) {
- super(looper, replySender, cb);
- mLogTag = MdnsProber.class.getSimpleName() + "/" + interfaceTag;
+ public MdnsProber(@NonNull Looper looper, @NonNull MdnsReplySender replySender,
+ @NonNull PacketRepeaterCallback<ProbingInfo> cb,
+ @NonNull SharedLog sharedLog) {
+ super(looper, replySender, cb, sharedLog);
}
/** Probing request to send with {@link MdnsProber}. */
@@ -118,11 +116,6 @@
}
}
- @NonNull
- @Override
- protected String getTag() {
- return mLogTag;
- }
@VisibleForTesting
protected long getInitialDelay() {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsQueryScheduler.java b/service-t/src/com/android/server/connectivity/mdns/MdnsQueryScheduler.java
new file mode 100644
index 0000000..3fcf0d4
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsQueryScheduler.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.mdns;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * The query scheduler class for calculating next query tasks parameters.
+ * <p>
+ * The class is not thread-safe and needs to be used on a consistent thread.
+ */
+public class MdnsQueryScheduler {
+
+ /**
+ * The argument for tracking the query tasks status.
+ */
+ public static class ScheduledQueryTaskArgs {
+ public final QueryTaskConfig config;
+ public final long timeToRun;
+ public final long minTtlExpirationTimeWhenScheduled;
+ public final long sessionId;
+
+ ScheduledQueryTaskArgs(@NonNull QueryTaskConfig config, long timeToRun,
+ long minTtlExpirationTimeWhenScheduled, long sessionId) {
+ this.config = config;
+ this.timeToRun = timeToRun;
+ this.minTtlExpirationTimeWhenScheduled = minTtlExpirationTimeWhenScheduled;
+ this.sessionId = sessionId;
+ }
+ }
+
+ @Nullable
+ private ScheduledQueryTaskArgs mLastScheduledQueryTaskArgs;
+
+ public MdnsQueryScheduler() {
+ }
+
+ /**
+ * Cancel the scheduled run. The method needed to be called when the scheduled task need to
+ * be canceled and rescheduling is not need.
+ */
+ public void cancelScheduledRun() {
+ mLastScheduledQueryTaskArgs = null;
+ }
+
+ /**
+ * Calculates ScheduledQueryTaskArgs for rescheduling the current task. Returns null if the
+ * rescheduling is not necessary.
+ */
+ @Nullable
+ public ScheduledQueryTaskArgs maybeRescheduleCurrentRun(long now,
+ long minRemainingTtl, long lastSentTime, long sessionId) {
+ if (mLastScheduledQueryTaskArgs == null) {
+ return null;
+ }
+ if (!mLastScheduledQueryTaskArgs.config.shouldUseQueryBackoff()) {
+ return null;
+ }
+
+ final long timeToRun = calculateTimeToRun(mLastScheduledQueryTaskArgs,
+ mLastScheduledQueryTaskArgs.config, now, minRemainingTtl, lastSentTime);
+
+ if (timeToRun <= mLastScheduledQueryTaskArgs.timeToRun) {
+ return null;
+ }
+
+ mLastScheduledQueryTaskArgs = new ScheduledQueryTaskArgs(mLastScheduledQueryTaskArgs.config,
+ timeToRun,
+ minRemainingTtl + now,
+ sessionId);
+ return mLastScheduledQueryTaskArgs;
+ }
+
+ /**
+ * Calculates the ScheduledQueryTaskArgs for the next run.
+ */
+ @NonNull
+ public ScheduledQueryTaskArgs scheduleNextRun(
+ @NonNull QueryTaskConfig currentConfig,
+ long minRemainingTtl,
+ long now,
+ long lastSentTime,
+ long sessionId) {
+ final QueryTaskConfig nextRunConfig = currentConfig.getConfigForNextRun();
+ final long timeToRun;
+ if (mLastScheduledQueryTaskArgs == null) {
+ timeToRun = now + nextRunConfig.delayUntilNextTaskWithoutBackoffMs;
+ } else {
+ timeToRun = calculateTimeToRun(mLastScheduledQueryTaskArgs,
+ nextRunConfig, now, minRemainingTtl, lastSentTime);
+ }
+ mLastScheduledQueryTaskArgs = new ScheduledQueryTaskArgs(nextRunConfig, timeToRun,
+ minRemainingTtl + now,
+ sessionId);
+ return mLastScheduledQueryTaskArgs;
+ }
+
+ /**
+ * Calculates the ScheduledQueryTaskArgs for the initial run.
+ */
+ public ScheduledQueryTaskArgs scheduleFirstRun(@NonNull QueryTaskConfig taskConfig,
+ long now, long minRemainingTtl, long currentSessionId) {
+ mLastScheduledQueryTaskArgs = new ScheduledQueryTaskArgs(taskConfig, now /* timeToRun */,
+ now + minRemainingTtl/* minTtlExpirationTimeWhenScheduled */,
+ currentSessionId);
+ return mLastScheduledQueryTaskArgs;
+ }
+
+ private static long calculateTimeToRun(@NonNull ScheduledQueryTaskArgs taskArgs,
+ QueryTaskConfig queryTaskConfig, long now, long minRemainingTtl, long lastSentTime) {
+ final long baseDelayInMs = queryTaskConfig.delayUntilNextTaskWithoutBackoffMs;
+ if (!queryTaskConfig.shouldUseQueryBackoff()) {
+ return lastSentTime + baseDelayInMs;
+ }
+ if (minRemainingTtl <= 0) {
+ // There's no service, or there is an expired service. In any case, schedule for the
+ // minimum time, which is the base delay.
+ return lastSentTime + baseDelayInMs;
+ }
+ // If the next TTL expiration time hasn't changed, then use previous calculated timeToRun.
+ if (lastSentTime < now
+ && taskArgs.minTtlExpirationTimeWhenScheduled == now + minRemainingTtl) {
+ // Use the original scheduling time if the TTL has not changed, to avoid continuously
+ // rescheduling to 80% of the remaining TTL as time passes
+ return taskArgs.timeToRun;
+ }
+ return Math.max(now + (long) (0.8 * minRemainingTtl), lastSentTime + baseDelayInMs);
+ }
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
index 8bc598d..16c7d27 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
@@ -22,8 +22,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.Log;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.MdnsRecordRepository.ReplyInfo;
import java.io.IOException;
@@ -43,21 +43,21 @@
public class MdnsReplySender {
private static final boolean DBG = MdnsAdvertiser.DBG;
private static final int MSG_SEND = 1;
-
- private final String mLogTag;
@NonNull
private final MdnsInterfaceSocket mSocket;
@NonNull
private final Handler mHandler;
@NonNull
private final byte[] mPacketCreationBuffer;
+ @NonNull
+ private final SharedLog mSharedLog;
- public MdnsReplySender(@NonNull String interfaceTag, @NonNull Looper looper,
- @NonNull MdnsInterfaceSocket socket, @NonNull byte[] packetCreationBuffer) {
+ public MdnsReplySender(@NonNull Looper looper, @NonNull MdnsInterfaceSocket socket,
+ @NonNull byte[] packetCreationBuffer, @NonNull SharedLog sharedLog) {
mHandler = new SendHandler(looper);
- mLogTag = MdnsReplySender.class.getSimpleName() + "/" + interfaceTag;
mSocket = socket;
mPacketCreationBuffer = packetCreationBuffer;
+ mSharedLog = sharedLog;
}
/**
@@ -69,7 +69,7 @@
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SEND, reply), reply.sendDelayMs);
if (DBG) {
- Log.v(mLogTag, "Scheduling " + reply);
+ mSharedLog.v("Scheduling " + reply);
}
}
@@ -134,7 +134,7 @@
@Override
public void handleMessage(@NonNull Message msg) {
final ReplyInfo replyInfo = (ReplyInfo) msg.obj;
- if (DBG) Log.v(mLogTag, "Sending " + replyInfo);
+ if (DBG) mSharedLog.v("Sending " + replyInfo);
final int flags = 0x8400; // Response, authoritative (rfc6762 18.4)
final MdnsPacket packet = new MdnsPacket(flags,
@@ -146,7 +146,7 @@
try {
sendNow(packet, replyInfo.destination);
} catch (IOException e) {
- Log.e(mLogTag, "Error sending MDNS response", e);
+ mSharedLog.e("Error sending MDNS response", e);
}
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
index a0a538e..2f10bde 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsResponseDecoder.java
@@ -23,7 +23,6 @@
import android.util.ArraySet;
import android.util.Pair;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
import com.android.server.connectivity.mdns.util.MdnsUtils;
import java.io.EOFException;
@@ -35,7 +34,6 @@
public class MdnsResponseDecoder {
public static final int SUCCESS = 0;
private static final String TAG = "MdnsResponseDecoder";
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
private final boolean allowMultipleSrvRecordsPerHost =
MdnsConfigs.allowMultipleSrvRecordsPerHost();
@Nullable private final String[] serviceType;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index b5fd8a0..53a7ab9 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -65,6 +65,7 @@
@NonNull private final SocketKey socketKey;
@NonNull private final SharedLog sharedLog;
@NonNull private final Handler handler;
+ @NonNull private final MdnsQueryScheduler mdnsQueryScheduler;
@NonNull private final Dependencies dependencies;
/**
* The service caches for each socket. It should be accessed from looper thread only.
@@ -82,9 +83,6 @@
// QueryTask for
// new subtypes. It stays the same between packets for same subtypes.
private long currentSessionId = 0;
-
- @Nullable
- private ScheduledQueryTaskArgs lastScheduledQueryTaskArgs;
private long lastSentTime;
private class QueryTaskHandler extends Handler {
@@ -97,7 +95,8 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_START_QUERYTASK: {
- final ScheduledQueryTaskArgs taskArgs = (ScheduledQueryTaskArgs) msg.obj;
+ final MdnsQueryScheduler.ScheduledQueryTaskArgs taskArgs =
+ (MdnsQueryScheduler.ScheduledQueryTaskArgs) msg.obj;
// QueryTask should be run immediately after being created (not be scheduled in
// advance). Because the result of "makeResponsesForResolve" depends on answers
// that were received before it is called, so to take into account all answers
@@ -126,15 +125,21 @@
tryRemoveServiceAfterTtlExpires();
- final QueryTaskConfig nextRunConfig =
- sentResult.taskArgs.config.getConfigForNextRun();
final long now = clock.elapsedRealtime();
lastSentTime = now;
final long minRemainingTtl = getMinRemainingTtl(now);
- final long timeToRun = calculateTimeToRun(lastScheduledQueryTaskArgs,
- nextRunConfig, now, minRemainingTtl, lastSentTime);
- scheduleNextRun(nextRunConfig, minRemainingTtl, now, timeToRun,
- lastScheduledQueryTaskArgs.sessionId);
+ MdnsQueryScheduler.ScheduledQueryTaskArgs args =
+ mdnsQueryScheduler.scheduleNextRun(
+ sentResult.taskArgs.config,
+ minRemainingTtl,
+ now,
+ lastSentTime,
+ sentResult.taskArgs.sessionId
+ );
+ dependencies.sendMessageDelayed(
+ handler,
+ handler.obtainMessage(EVENT_START_QUERYTASK, args),
+ calculateTimeToNextTask(args, now, sharedLog));
break;
}
default:
@@ -219,6 +224,7 @@
this.handler = new QueryTaskHandler(looper);
this.dependencies = dependencies;
this.serviceCache = serviceCache;
+ this.mdnsQueryScheduler = new MdnsQueryScheduler();
}
private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(
@@ -300,6 +306,7 @@
}
// Remove the next scheduled periodical task.
removeScheduledTask();
+ mdnsQueryScheduler.cancelScheduledRun();
// Keep tracking the ScheduledFuture for the task so we can cancel it if caller is not
// interested anymore.
final QueryTaskConfig taskConfig = new QueryTaskConfig(
@@ -312,18 +319,25 @@
if (lastSentTime == 0) {
lastSentTime = now;
}
+ final long minRemainingTtl = getMinRemainingTtl(now);
if (hadReply) {
- final QueryTaskConfig queryTaskConfig = taskConfig.getConfigForNextRun();
- final long minRemainingTtl = getMinRemainingTtl(now);
- final long timeToRun = now + queryTaskConfig.delayUntilNextTaskWithoutBackoffMs;
- scheduleNextRun(
- queryTaskConfig, minRemainingTtl, now, timeToRun, currentSessionId);
+ MdnsQueryScheduler.ScheduledQueryTaskArgs args =
+ mdnsQueryScheduler.scheduleNextRun(
+ taskConfig,
+ minRemainingTtl,
+ now,
+ lastSentTime,
+ currentSessionId
+ );
+ dependencies.sendMessageDelayed(
+ handler,
+ handler.obtainMessage(EVENT_START_QUERYTASK, args),
+ calculateTimeToNextTask(args, now, sharedLog));
} else {
final List<MdnsResponse> servicesToResolve = makeResponsesForResolve(socketKey);
- lastScheduledQueryTaskArgs = new ScheduledQueryTaskArgs(taskConfig, now /* timeToRun */,
- now + getMinRemainingTtl(now)/* minTtlExpirationTimeWhenScheduled */,
- currentSessionId);
- final QueryTask queryTask = new QueryTask(lastScheduledQueryTaskArgs, servicesToResolve,
+ final QueryTask queryTask = new QueryTask(
+ mdnsQueryScheduler.scheduleFirstRun(taskConfig, now,
+ minRemainingTtl, currentSessionId), servicesToResolve,
servicesToResolve.size() < listeners.size() /* sendDiscoveryQueries */);
executor.submit(queryTask);
}
@@ -341,7 +355,6 @@
sharedLog.log("Remove EVENT_START_QUERYTASK"
+ ", current session: " + currentSessionId);
++currentSessionId;
- lastScheduledQueryTaskArgs = null;
}
private boolean responseMatchesOptions(@NonNull MdnsResponse response,
@@ -378,6 +391,7 @@
}
if (listeners.isEmpty()) {
removeScheduledTask();
+ mdnsQueryScheduler.cancelScheduledRun();
}
return listeners.isEmpty();
}
@@ -421,18 +435,18 @@
serviceCache.addOrUpdateService(serviceType, socketKey, response);
}
}
- if (dependencies.hasMessages(handler, EVENT_START_QUERYTASK)
- && lastScheduledQueryTaskArgs != null
- && lastScheduledQueryTaskArgs.config.shouldUseQueryBackoff()) {
+ if (dependencies.hasMessages(handler, EVENT_START_QUERYTASK)) {
final long now = clock.elapsedRealtime();
final long minRemainingTtl = getMinRemainingTtl(now);
- final long timeToRun = calculateTimeToRun(lastScheduledQueryTaskArgs,
- lastScheduledQueryTaskArgs.config, now,
- minRemainingTtl, lastSentTime);
- if (timeToRun > lastScheduledQueryTaskArgs.timeToRun) {
- QueryTaskConfig lastTaskConfig = lastScheduledQueryTaskArgs.config;
+ MdnsQueryScheduler.ScheduledQueryTaskArgs args =
+ mdnsQueryScheduler.maybeRescheduleCurrentRun(now, minRemainingTtl,
+ lastSentTime, currentSessionId + 1);
+ if (args != null) {
removeScheduledTask();
- scheduleNextRun(lastTaskConfig, minRemainingTtl, now, timeToRun, currentSessionId);
+ dependencies.sendMessageDelayed(
+ handler,
+ handler.obtainMessage(EVENT_START_QUERYTASK, args),
+ calculateTimeToNextTask(args, now, sharedLog));
}
}
}
@@ -464,6 +478,7 @@
}
}
removeScheduledTask();
+ mdnsQueryScheduler.cancelScheduledRun();
}
private void onResponseModified(@NonNull MdnsResponse response) {
@@ -599,28 +614,14 @@
}
}
- private static class ScheduledQueryTaskArgs {
- private final QueryTaskConfig config;
- private final long timeToRun;
- private final long minTtlExpirationTimeWhenScheduled;
- private final long sessionId;
-
- ScheduledQueryTaskArgs(@NonNull QueryTaskConfig config, long timeToRun,
- long minTtlExpirationTimeWhenScheduled, long sessionId) {
- this.config = config;
- this.timeToRun = timeToRun;
- this.minTtlExpirationTimeWhenScheduled = minTtlExpirationTimeWhenScheduled;
- this.sessionId = sessionId;
- }
- }
private static class QuerySentArguments {
private final int transactionId;
private final List<String> subTypes = new ArrayList<>();
- private final ScheduledQueryTaskArgs taskArgs;
+ private final MdnsQueryScheduler.ScheduledQueryTaskArgs taskArgs;
QuerySentArguments(int transactionId, @NonNull List<String> subTypes,
- @NonNull ScheduledQueryTaskArgs taskArgs) {
+ @NonNull MdnsQueryScheduler.ScheduledQueryTaskArgs taskArgs) {
this.transactionId = transactionId;
this.subTypes.addAll(subTypes);
this.taskArgs = taskArgs;
@@ -629,12 +630,10 @@
// A FutureTask that enqueues a single query, and schedule a new FutureTask for the next task.
private class QueryTask implements Runnable {
-
- private final ScheduledQueryTaskArgs taskArgs;
+ private final MdnsQueryScheduler.ScheduledQueryTaskArgs taskArgs;
private final List<MdnsResponse> servicesToResolve = new ArrayList<>();
private final boolean sendDiscoveryQueries;
-
- QueryTask(@NonNull ScheduledQueryTaskArgs taskArgs,
+ QueryTask(@NonNull MdnsQueryScheduler.ScheduledQueryTaskArgs taskArgs,
@NonNull List<MdnsResponse> servicesToResolve, boolean sendDiscoveryQueries) {
this.taskArgs = taskArgs;
this.servicesToResolve.addAll(servicesToResolve);
@@ -657,7 +656,8 @@
taskArgs.config.onlyUseIpv6OnIpv6OnlyNetworks,
sendDiscoveryQueries,
servicesToResolve,
- clock)
+ clock,
+ sharedLog)
.call();
} catch (RuntimeException e) {
sharedLog.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s",
@@ -670,27 +670,6 @@
}
}
- private static long calculateTimeToRun(@NonNull ScheduledQueryTaskArgs taskArgs,
- QueryTaskConfig queryTaskConfig, long now, long minRemainingTtl, long lastSentTime) {
- final long baseDelayInMs = queryTaskConfig.delayUntilNextTaskWithoutBackoffMs;
- if (!queryTaskConfig.shouldUseQueryBackoff()) {
- return lastSentTime + baseDelayInMs;
- }
- if (minRemainingTtl <= 0) {
- // There's no service, or there is an expired service. In any case, schedule for the
- // minimum time, which is the base delay.
- return lastSentTime + baseDelayInMs;
- }
- // If the next TTL expiration time hasn't changed, then use previous calculated timeToRun.
- if (lastSentTime < now
- && taskArgs.minTtlExpirationTimeWhenScheduled == now + minRemainingTtl) {
- // Use the original scheduling time if the TTL has not changed, to avoid continuously
- // rescheduling to 80% of the remaining TTL as time passes
- return taskArgs.timeToRun;
- }
- return Math.max(now + (long) (0.8 * minRemainingTtl), lastSentTime + baseDelayInMs);
- }
-
private long getMinRemainingTtl(long now) {
long minRemainingTtl = Long.MAX_VALUE;
for (MdnsResponse response : serviceCache.getCachedServices(serviceType, socketKey)) {
@@ -710,19 +689,11 @@
return minRemainingTtl == Long.MAX_VALUE ? 0 : minRemainingTtl;
}
- @NonNull
- private void scheduleNextRun(@NonNull QueryTaskConfig nextRunConfig,
- long minRemainingTtl,
- long timeWhenScheduled, long timeToRun, long sessionId) {
- lastScheduledQueryTaskArgs = new ScheduledQueryTaskArgs(nextRunConfig, timeToRun,
- minRemainingTtl + timeWhenScheduled, sessionId);
- // The timeWhenScheduled could be greater than the timeToRun if the Runnable is delayed.
- long timeToNextTasksWithBackoffInMs = Math.max(timeToRun - timeWhenScheduled, 0);
+ private static long calculateTimeToNextTask(MdnsQueryScheduler.ScheduledQueryTaskArgs args,
+ long now, SharedLog sharedLog) {
+ long timeToNextTasksWithBackoffInMs = Math.max(args.timeToRun - now, 0);
sharedLog.log(String.format("Next run: sessionId: %d, in %d ms",
- lastScheduledQueryTaskArgs.sessionId, timeToNextTasksWithBackoffInMs));
- dependencies.sendMessageDelayed(
- handler,
- handler.obtainMessage(EVENT_START_QUERYTASK, lastScheduledQueryTaskArgs),
- timeToNextTasksWithBackoffInMs);
+ args.sessionId, timeToNextTasksWithBackoffInMs));
+ return timeToNextTasksWithBackoffInMs;
}
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java
index cdd9f76..d690032 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocket.java
@@ -21,7 +21,7 @@
import android.net.Network;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -37,8 +37,6 @@
* @see MulticastSocket for javadoc of each public method.
*/
public class MdnsSocket {
- private static final MdnsLogger LOGGER = new MdnsLogger("MdnsSocket");
-
static final int INTERFACE_INDEX_UNSPECIFIED = -1;
public static final InetSocketAddress MULTICAST_IPV4_ADDRESS =
new InetSocketAddress(MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
@@ -47,19 +45,22 @@
private final MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider;
private final MulticastSocket multicastSocket;
private boolean isOnIPv6OnlyNetwork;
+ private final SharedLog sharedLog;
public MdnsSocket(
- @NonNull MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider, int port)
+ @NonNull MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider, int port,
+ SharedLog sharedLog)
throws IOException {
- this(multicastNetworkInterfaceProvider, new MulticastSocket(port));
+ this(multicastNetworkInterfaceProvider, new MulticastSocket(port), sharedLog);
}
@VisibleForTesting
MdnsSocket(@NonNull MulticastNetworkInterfaceProvider multicastNetworkInterfaceProvider,
- MulticastSocket multicastSocket) throws IOException {
+ MulticastSocket multicastSocket, SharedLog sharedLog) throws IOException {
this.multicastNetworkInterfaceProvider = multicastNetworkInterfaceProvider;
this.multicastNetworkInterfaceProvider.startWatchingConnectivityChanges();
this.multicastSocket = multicastSocket;
+ this.sharedLog = sharedLog;
// RFC Spec: https://tools.ietf.org/html/rfc6762
// Time to live is set 255, which is similar to the jMDNS implementation.
multicastSocket.setTimeToLive(255);
@@ -130,7 +131,7 @@
try {
return multicastSocket.getNetworkInterface().getIndex();
} catch (SocketException e) {
- LOGGER.e("Failed to retrieve interface index for socket.", e);
+ sharedLog.e("Failed to retrieve interface index for socket.", e);
return -1;
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
index 9c9812d..d18a19b 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketClient.java
@@ -27,7 +27,7 @@
import android.text.format.DateUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -57,7 +57,6 @@
private static final String CAST_SENDER_LOG_SOURCE = "CAST_SENDER_SDK";
private static final String CAST_PREFS_NAME = "google_cast";
private static final String PREF_CAST_SENDER_ID = "PREF_CAST_SENDER_ID";
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
private static final String MULTICAST_TYPE = "multicast";
private static final String UNICAST_TYPE = "unicast";
@@ -105,8 +104,11 @@
@Nullable private Timer logMdnsPacketTimer;
private AtomicInteger packetsCount;
@Nullable private Timer checkMulticastResponseTimer;
+ private final SharedLog sharedLog;
- public MdnsSocketClient(@NonNull Context context, @NonNull MulticastLock multicastLock) {
+ public MdnsSocketClient(@NonNull Context context, @NonNull MulticastLock multicastLock,
+ SharedLog sharedLog) {
+ this.sharedLog = sharedLog;
this.context = context;
this.multicastLock = multicastLock;
if (useSeparateSocketForUnicast) {
@@ -125,7 +127,7 @@
@Override
public synchronized void startDiscovery() throws IOException {
if (multicastSocket != null) {
- LOGGER.w("Discovery is already in progress.");
+ sharedLog.w("Discovery is already in progress.");
return;
}
@@ -136,11 +138,11 @@
shouldStopSocketLoop = false;
try {
// TODO (changed when importing code): consider setting thread stats tag
- multicastSocket = createMdnsSocket(MdnsConstants.MDNS_PORT);
+ multicastSocket = createMdnsSocket(MdnsConstants.MDNS_PORT, sharedLog);
multicastSocket.joinGroup();
if (useSeparateSocketForUnicast) {
// For unicast, use port 0 and the system will assign it with any available port.
- unicastSocket = createMdnsSocket(0);
+ unicastSocket = createMdnsSocket(0, sharedLog);
}
multicastLock.acquire();
} catch (IOException e) {
@@ -164,7 +166,7 @@
@RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE)
@Override
public void stopDiscovery() {
- LOGGER.log("Stop discovery.");
+ sharedLog.log("Stop discovery.");
if (multicastSocket == null && unicastSocket == null) {
return;
}
@@ -233,7 +235,7 @@
private void sendMdnsPacket(DatagramPacket packet, Queue<DatagramPacket> packetQueueToUse,
boolean onlyUseIpv6OnIpv6OnlyNetworks) {
if (shouldStopSocketLoop && !MdnsConfigs.allowAddMdnsPacketAfterDiscoveryStops()) {
- LOGGER.w("sendMdnsPacket() is called after discovery already stopped");
+ sharedLog.w("sendMdnsPacket() is called after discovery already stopped");
return;
}
@@ -260,7 +262,7 @@
private void createAndStartSendThread() {
if (sendThread != null) {
- LOGGER.w("A socket thread already exists.");
+ sharedLog.w("A socket thread already exists.");
return;
}
sendThread = new Thread(this::sendThreadMain);
@@ -270,7 +272,7 @@
private void createAndStartReceiverThreads() {
if (multicastReceiveThread != null) {
- LOGGER.w("A multicast receiver thread already exists.");
+ sharedLog.w("A multicast receiver thread already exists.");
return;
}
multicastReceiveThread =
@@ -292,12 +294,12 @@
}
private void triggerSendThread() {
- LOGGER.log("Trigger send thread.");
+ sharedLog.log("Trigger send thread.");
Thread sendThread = this.sendThread;
if (sendThread != null) {
sendThread.interrupt();
} else {
- LOGGER.w("Socket thread is null");
+ sharedLog.w("Socket thread is null");
}
}
@@ -314,9 +316,9 @@
}
private void waitForSendThreadToStop() {
- LOGGER.log("wait For Send Thread To Stop");
+ sharedLog.log("wait For Send Thread To Stop");
if (sendThread == null) {
- LOGGER.w("socket thread is already dead.");
+ sharedLog.w("socket thread is already dead.");
return;
}
waitForThread(sendThread);
@@ -331,7 +333,7 @@
thread.interrupt();
thread.join(waitMs);
if (thread.isAlive()) {
- LOGGER.w("Failed to join thread: " + thread);
+ sharedLog.w("Failed to join thread: " + thread);
}
break;
} catch (InterruptedException e) {
@@ -390,13 +392,13 @@
}
}
} finally {
- LOGGER.log("Send thread stopped.");
+ sharedLog.log("Send thread stopped.");
try {
if (multicastSocket != null) {
multicastSocket.leaveGroup();
}
} catch (Exception t) {
- LOGGER.e("Failed to leave the group.", t);
+ sharedLog.e("Failed to leave the group.", t);
}
// Close the socket first. This is the only way to interrupt a blocking receive.
@@ -409,7 +411,7 @@
unicastSocket.close();
}
} catch (RuntimeException t) {
- LOGGER.e("Failed to close the mdns socket.", t);
+ sharedLog.e("Failed to close the mdns socket.", t);
}
}
}
@@ -439,11 +441,11 @@
}
} catch (IOException e) {
if (!shouldStopSocketLoop) {
- LOGGER.e("Failed to receive mDNS packets.", e);
+ sharedLog.e("Failed to receive mDNS packets.", e);
}
}
}
- LOGGER.log("Receive thread stopped.");
+ sharedLog.log("Receive thread stopped.");
}
private int processResponsePacket(@NonNull DatagramPacket packet, String responseType,
@@ -454,7 +456,7 @@
try {
response = MdnsResponseDecoder.parseResponse(packet.getData(), packet.getLength());
} catch (MdnsPacket.ParseException e) {
- LOGGER.w(String.format("Error while decoding %s packet (%d): %d",
+ sharedLog.w(String.format("Error while decoding %s packet (%d): %d",
responseType, packetNumber, e.code));
if (callback != null) {
callback.onFailedToParseMdnsResponse(packetNumber, e.code,
@@ -476,8 +478,9 @@
}
@VisibleForTesting
- MdnsSocket createMdnsSocket(int port) throws IOException {
- return new MdnsSocket(new MulticastNetworkInterfaceProvider(context), port);
+ MdnsSocket createMdnsSocket(int port, SharedLog sharedLog) throws IOException {
+ return new MdnsSocket(new MulticastNetworkInterfaceProvider(context, sharedLog), port,
+ sharedLog);
}
private void sendPackets(List<DatagramPacket> packets, MdnsSocket socket) {
@@ -487,7 +490,7 @@
break;
}
try {
- LOGGER.log("Sending a %s mDNS packet...", requestType);
+ sharedLog.log(String.format("Sending a %s mDNS packet...", requestType));
socket.send(packet);
// Start the timer task to monitor the response.
@@ -516,7 +519,7 @@
}
if ((!receivedMulticastResponse)
&& receivedUnicastResponse) {
- LOGGER.e(String.format(
+ sharedLog.e(String.format(
"Haven't received multicast response"
+ " in the last %d ms.",
checkMulticastResponseIntervalMs));
@@ -531,7 +534,7 @@
}
}
} catch (IOException e) {
- LOGGER.e(String.format("Failed to send a %s mDNS packet.", requestType), e);
+ sharedLog.e(String.format("Failed to send a %s mDNS packet.", requestType), e);
}
}
packets.clear();
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
index 6925b49..23c5a4d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -44,7 +44,6 @@
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -118,7 +117,7 @@
if (mWifiP2pTetherInterface != null) {
if (newP2pIface != null) {
- Log.wtf(TAG, "Wifi p2p interface is changed from " + mWifiP2pTetherInterface
+ mSharedLog.wtf("Wifi p2p interface is changed from " + mWifiP2pTetherInterface
+ " to " + newP2pIface + " without null broadcast");
}
// Remove the socket.
@@ -133,7 +132,7 @@
if (newP2pIface != null && !socketAlreadyExists) {
// Create a socket for wifi p2p interface.
final int ifaceIndex =
- mDependencies.getNetworkInterfaceIndexByName(newP2pIface);
+ mDependencies.getNetworkInterfaceIndexByName(newP2pIface, mSharedLog);
createSocket(LOCAL_NET, createLPForTetheredInterface(newP2pIface, ifaceIndex));
}
}
@@ -233,21 +232,23 @@
/*** Create a MdnsInterfaceSocket */
public MdnsInterfaceSocket createMdnsInterfaceSocket(
@NonNull NetworkInterface networkInterface, int port, @NonNull Looper looper,
- @NonNull byte[] packetReadBuffer) throws IOException {
- return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer);
+ @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog) throws IOException {
+ return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer,
+ sharedLog);
}
/*** Get network interface by given interface name */
- public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName) {
+ public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName,
+ @NonNull SharedLog sharedLog) {
final NetworkInterface iface;
try {
iface = NetworkInterface.getByName(ifaceName);
} catch (SocketException e) {
- Log.e(TAG, "Error querying interface", e);
+ sharedLog.e("Error querying interface", e);
return IFACE_IDX_NOT_EXIST;
}
if (iface == null) {
- Log.e(TAG, "Interface not found: " + ifaceName);
+ sharedLog.e("Interface not found: " + ifaceName);
return IFACE_IDX_NOT_EXIST;
}
return iface.getIndex();
@@ -335,7 +336,7 @@
ensureRunningOnHandlerThread(mHandler);
mRequestStop = false; // Reset stop request flag.
if (mMonitoringSockets) {
- Log.d(TAG, "Already monitoring sockets.");
+ mSharedLog.v("Already monitoring sockets.");
return;
}
mSharedLog.i("Start monitoring sockets.");
@@ -390,7 +391,7 @@
public void requestStopWhenInactive() {
ensureRunningOnHandlerThread(mHandler);
if (!mMonitoringSockets) {
- Log.d(TAG, "Monitoring sockets hasn't been started.");
+ mSharedLog.v("Monitoring sockets hasn't been started.");
return;
}
mRequestStop = true;
@@ -410,7 +411,7 @@
mActiveNetworksLinkProperties.put(network, lp);
if (!matchRequestedNetwork(network)) {
if (DBG) {
- Log.d(TAG, "Ignore LinkProperties change. There is no request for the"
+ mSharedLog.v("Ignore LinkProperties change. There is no request for the"
+ " Network:" + network);
}
return;
@@ -428,7 +429,7 @@
@NonNull final List<LinkAddress> updatedAddresses) {
for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) {
String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i);
- if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName)
+ if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName, mSharedLog)
== ifaceIndex) {
updateSocketInfoAddress(null /* network */,
mTetherInterfaceSockets.valueAt(i), updatedAddresses);
@@ -462,7 +463,7 @@
// tethering are only created if there is a request for all networks (interfaces).
// Therefore, only update the interface list and skip this change if no such request.
if (DBG) {
- Log.d(TAG, "Ignore tether interfaces change. There is no request for all"
+ mSharedLog.v("Ignore tether interfaces change. There is no request for all"
+ " networks.");
}
current.clear();
@@ -482,7 +483,7 @@
continue;
}
- int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name);
+ int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name, mSharedLog);
createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex));
}
for (String name : interfaceDiff.removed) {
@@ -495,7 +496,7 @@
private void createSocket(NetworkKey networkKey, LinkProperties lp) {
final String interfaceName = lp.getInterfaceName();
if (interfaceName == null) {
- Log.e(TAG, "Can not create socket with null interface name.");
+ mSharedLog.e("Can not create socket with null interface name.");
return;
}
@@ -514,7 +515,7 @@
if (knownTransports != null) {
transports = knownTransports;
} else {
- Log.wtf(TAG, "transports is missing for key: " + networkKey);
+ mSharedLog.wtf("transports is missing for key: " + networkKey);
transports = new int[0];
}
}
@@ -525,7 +526,8 @@
mSharedLog.log("Create socket on net:" + networkKey + ", ifName:" + interfaceName);
final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket(
networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper,
- mPacketReadBuffer);
+ mPacketReadBuffer, mSharedLog.forSubComponent(
+ MdnsInterfaceSocket.class.getSimpleName() + "/" + interfaceName));
final List<LinkAddress> addresses = lp.getLinkAddresses();
final Network network =
networkKey == LOCAL_NET ? null : ((NetworkAsKey) networkKey).mNetwork;
@@ -637,7 +639,7 @@
final LinkProperties lp = mActiveNetworksLinkProperties.get(network);
if (lp == null) {
// The requested network is not existed. Maybe wait for LinkProperties change later.
- if (DBG) Log.d(TAG, "There is no LinkProperties for this network:" + network);
+ if (DBG) mSharedLog.v("There is no LinkProperties for this network:" + network);
return;
}
createSocket(new NetworkAsKey(network), lp);
@@ -652,7 +654,8 @@
private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) {
final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName);
if (socketInfo == null) {
- int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName);
+ int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName,
+ mSharedLog);
createSocket(
LOCAL_NET,
createLPForTetheredInterface(interfaceName, ifaceIndex));
diff --git a/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
index f248c98..da82e96 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
@@ -22,7 +22,7 @@
import android.net.Network;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
import java.net.Inet4Address;
@@ -41,7 +41,7 @@
public class MulticastNetworkInterfaceProvider {
private static final String TAG = "MdnsNIProvider";
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
+ private final SharedLog sharedLog;
private static final boolean PREFER_IPV6 = MdnsConfigs.preferIpv6();
private final List<NetworkInterfaceWrapper> multicastNetworkInterfaces = new ArrayList<>();
@@ -51,10 +51,12 @@
private volatile boolean connectivityChanged = true;
@SuppressWarnings("nullness:methodref.receiver.bound")
- public MulticastNetworkInterfaceProvider(@NonNull Context context) {
+ public MulticastNetworkInterfaceProvider(@NonNull Context context,
+ @NonNull SharedLog sharedLog) {
+ this.sharedLog = sharedLog;
// IMPORT CHANGED
this.connectivityMonitor = new ConnectivityMonitorWithConnectivityManager(
- context, this::onConnectivityChanged);
+ context, this::onConnectivityChanged, sharedLog);
}
private synchronized void onConnectivityChanged() {
@@ -83,7 +85,7 @@
connectivityChanged = false;
updateMulticastNetworkInterfaces();
if (multicastNetworkInterfaces.isEmpty()) {
- LOGGER.log("No network interface available for mDNS scanning.");
+ sharedLog.log("No network interface available for mDNS scanning.");
}
}
return new ArrayList<>(multicastNetworkInterfaces);
@@ -93,7 +95,7 @@
multicastNetworkInterfaces.clear();
List<NetworkInterfaceWrapper> networkInterfaceWrappers = getNetworkInterfaces();
for (NetworkInterfaceWrapper interfaceWrapper : networkInterfaceWrappers) {
- if (canScanOnInterface(interfaceWrapper)) {
+ if (canScanOnInterface(interfaceWrapper, sharedLog)) {
multicastNetworkInterfaces.add(interfaceWrapper);
}
}
@@ -133,10 +135,10 @@
}
}
} catch (SocketException e) {
- LOGGER.e("Failed to get network interfaces.", e);
+ sharedLog.e("Failed to get network interfaces.", e);
} catch (NullPointerException e) {
// Android R has a bug that could lead to a NPE. See b/159277702.
- LOGGER.e("Failed to call getNetworkInterfaces API", e);
+ sharedLog.e("Failed to call getNetworkInterfaces API", e);
}
return networkInterfaceWrappers;
@@ -148,7 +150,8 @@
}
/*** Check whether given network interface can support mdns */
- private static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface) {
+ private static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface,
+ @NonNull SharedLog sharedLog) {
try {
if ((networkInterface == null)
|| networkInterface.isLoopback()
@@ -160,7 +163,7 @@
}
return hasInet4Address(networkInterface) || hasInet6Address(networkInterface);
} catch (IOException e) {
- LOGGER.e(String.format("Failed to check interface %s.",
+ sharedLog.e(String.format("Failed to check interface %s.",
networkInterface.getNetworkInterface().getDisplayName()), e);
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
index c21c903..6f16436 100644
--- a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
+++ b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
@@ -20,7 +20,6 @@
import android.net.LinkAddress;
import android.os.Handler;
import android.system.OsConstants;
-import android.util.Log;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.ip.NetlinkMonitor;
@@ -37,6 +36,8 @@
public class SocketNetlinkMonitor extends NetlinkMonitor implements AbstractSocketNetlinkMonitor {
public static final String TAG = SocketNetlinkMonitor.class.getSimpleName();
+ @NonNull
+ private final SharedLog mSharedLog;
@NonNull
private final MdnsSocketProvider.NetLinkMonitorCallBack mCb;
@@ -46,6 +47,7 @@
super(handler, log, TAG, OsConstants.NETLINK_ROUTE,
NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR);
mCb = cb;
+ mSharedLog = log;
}
@Override
public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
@@ -71,7 +73,7 @@
mCb.deleteInterfaceAddress(ifaddrMsg.index, la);
break;
default:
- Log.e(TAG, "Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type);
+ mSharedLog.e("Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type);
}
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 6635fd3..3f4113a 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -3303,6 +3303,7 @@
private static native long nativeGetTotalStat(int type);
private static native long nativeGetIfaceStat(String iface, int type);
+ private static native long nativeGetIfIndexStat(int ifindex, int type);
private static native long nativeGetUidStat(int uid, int type);
/** Initializes and registers the Perfetto Network Trace data source */
diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
index a367d9d..e1e2585 100644
--- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
@@ -24,9 +24,12 @@
import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MTU;
+import static com.android.net.module.util.NetworkStackConstants.IP_MTU;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TargetApi;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -35,6 +38,7 @@
import android.net.TrafficStats;
import android.net.shared.PrivateDnsConfig;
import android.net.util.NetworkConstants;
+import android.os.Build;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
@@ -213,14 +217,10 @@
mLinkProperties.addDnsServer(TEST_DNS6);
}
- final int lpMtu = mLinkProperties.getMtu();
- final int mtu = lpMtu > 0 ? lpMtu : ETHER_MTU;
for (RouteInfo route : mLinkProperties.getRoutes()) {
if (route.getType() == RouteInfo.RTN_UNICAST && route.hasGateway()) {
- InetAddress gateway = route.getGateway();
- // Use mtu in the route if exists. Otherwise, use the one in the link property.
- final int routeMtu = route.getMtu();
- prepareIcmpMeasurements(gateway, (routeMtu > 0) ? routeMtu : mtu);
+ final InetAddress gateway = route.getGateway();
+ prepareIcmpMeasurements(gateway);
if (route.isIPv6Default()) {
prepareExplicitSourceIcmpMeasurements(gateway);
}
@@ -228,7 +228,7 @@
}
for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
- prepareIcmpMeasurements(nameserver, mtu);
+ prepareIcmpMeasurements(nameserver);
prepareDnsMeasurement(nameserver);
// Unlike the DnsResolver which doesn't do certificate validation in opportunistic mode,
@@ -285,24 +285,29 @@
// calculation.
if (addr instanceof Inet6Address) {
return IPV6_HEADER_LEN + ICMP_HEADER_LEN;
+ } else {
+ return IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN;
}
} catch (UnknownHostException e) {
- Log.e(TAG, "Create InetAddress fail(" + target + "): " + e);
+ throw new AssertionError("Create InetAddress fail(" + target + ")", e);
}
-
- return IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN;
}
- private void prepareIcmpMeasurements(@NonNull InetAddress target, int targetNetworkMtu) {
+ private void prepareIcmpMeasurements(@NonNull InetAddress target) {
+ int mtu = getMtuForTarget(target);
+ // If getMtuForTarget fails, it doesn't matter what mtu is used because connect can't
+ // succeed anyway
+ if (mtu <= 0) mtu = mLinkProperties.getMtu();
+ if (mtu <= 0) mtu = ETHER_MTU;
// Test with different size payload ICMP.
// 1. Test with 0 payload.
addPayloadIcmpMeasurement(target, 0);
final int header = getHeaderLen(target);
// 2. Test with full size MTU.
- addPayloadIcmpMeasurement(target, targetNetworkMtu - header);
+ addPayloadIcmpMeasurement(target, mtu - header);
// 3. If v6, make another measurement with the full v6 min MTU, unless that's what
// was done above.
- if ((target instanceof Inet6Address) && (targetNetworkMtu != IPV6_MIN_MTU)) {
+ if ((target instanceof Inet6Address) && (mtu != IPV6_MIN_MTU)) {
addPayloadIcmpMeasurement(target, IPV6_MIN_MTU - header);
}
}
@@ -321,6 +326,35 @@
}
}
+ /**
+ * Open a socket to the target address and return the mtu from that socket
+ *
+ * If the MTU can't be obtained for some reason (e.g. the target is unreachable) this will
+ * return -1.
+ *
+ * @param target the destination address
+ * @return the mtu to that destination, or -1
+ */
+ // getsockoptInt is S+, but this service code and only installs on S, so it's safe to ignore
+ // the lint warnings by using @TargetApi.
+ @TargetApi(Build.VERSION_CODES.S)
+ private int getMtuForTarget(InetAddress target) {
+ final int family = target instanceof Inet4Address ? AF_INET : AF_INET6;
+ try {
+ final FileDescriptor socket = Os.socket(family, SOCK_DGRAM, 0);
+ mNetwork.bindSocket(socket);
+ Os.connect(socket, target, 0);
+ if (family == AF_INET) {
+ return Os.getsockoptInt(socket, IPPROTO_IP, IP_MTU);
+ } else {
+ return Os.getsockoptInt(socket, IPPROTO_IPV6, IPV6_MTU);
+ }
+ } catch (ErrnoException | IOException e) {
+ Log.e(TAG, "Can't get MTU for destination " + target, e);
+ return -1;
+ }
+ }
+
private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
InetAddress source = l.getAddress();
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 6b21dac..1c99722 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -29,6 +29,7 @@
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isBatterySaverSupported;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isDozeModeSupported;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.restrictBackgroundValueToString;
+import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackgroundInternal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -52,9 +53,9 @@
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Bundle;
+import android.os.PowerManager;
import android.os.RemoteCallback;
import android.os.SystemClock;
-import android.os.PowerManager;
import android.provider.DeviceConfig;
import android.service.notification.NotificationListenerService;
import android.util.Log;
@@ -180,6 +181,12 @@
mServiceClient.bind();
mPowerManager = mContext.getSystemService(PowerManager.class);
executeShellCommand("cmd netpolicy start-watching " + mUid);
+ // Some of the test cases assume that Data saver mode is initially disabled, which might not
+ // always be the case. Therefore, explicitly disable it before running the tests.
+ // Invoke setRestrictBackgroundInternal() directly instead of going through
+ // setRestrictBackground(), as some devices do not fully support the Data saver mode but
+ // still have certain parts of it enabled by default.
+ setRestrictBackgroundInternal(false);
setAppIdle(false);
mLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
index deca6a2..8c38b44 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java
@@ -344,7 +344,7 @@
setRestrictBackgroundInternal(enabled);
}
- private static void setRestrictBackgroundInternal(boolean enabled) {
+ static void setRestrictBackgroundInternal(boolean enabled) {
executeShellCommand("cmd netpolicy set restrict-background " + enabled);
final String output = executeShellCommand("cmd netpolicy get restrict-background");
final String expectedSuffix = enabled ? "enabled" : "disabled";
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 49620b0..7731ac9 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -16,6 +16,7 @@
package android.net.cts
import android.Manifest.permission.MANAGE_TEST_NETWORKS
+import android.Manifest.permission.NETWORK_SETTINGS
import android.app.compat.CompatChanges
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
@@ -60,6 +61,8 @@
import android.net.nsd.NsdManager.RegistrationListener
import android.net.nsd.NsdManager.ResolveListener
import android.net.nsd.NsdServiceInfo
+import android.net.nsd.OffloadEngine
+import android.net.nsd.OffloadServiceInfo
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
@@ -353,6 +356,22 @@
}
}
+ private class TestNsdOffloadEngine : OffloadEngine,
+ NsdRecord<TestNsdOffloadEngine.OffloadEvent>() {
+ sealed class OffloadEvent : NsdEvent {
+ data class AddOrUpdateEvent(val info: OffloadServiceInfo) : OffloadEvent()
+ data class RemoveEvent(val info: OffloadServiceInfo) : OffloadEvent()
+ }
+
+ override fun onOffloadServiceUpdated(info: OffloadServiceInfo) {
+ add(OffloadEvent.AddOrUpdateEvent(info))
+ }
+
+ override fun onOffloadServiceRemoved(info: OffloadServiceInfo) {
+ add(OffloadEvent.RemoveEvent(info))
+ }
+ }
+
@Before
fun setUp() {
handlerThread.start()
@@ -858,6 +877,52 @@
}
}
+ fun checkOffloadServiceInfo(serviceInfo: OffloadServiceInfo) {
+ assertEquals(serviceName, serviceInfo.key.serviceName)
+ assertEquals(serviceType, serviceInfo.key.serviceType)
+ assertEquals(listOf<String>("_subtype"), serviceInfo.subtypes)
+ assertTrue(serviceInfo.hostname.startsWith("Android_"))
+ assertTrue(serviceInfo.hostname.endsWith("local"))
+ assertEquals(0, serviceInfo.priority)
+ assertEquals(OffloadEngine.OFFLOAD_TYPE_REPLY.toLong(), serviceInfo.offloadType)
+ }
+
+ @Test
+ fun testNsdManager_registerOffloadEngine() {
+ val targetSdkVersion = context.packageManager
+ .getTargetSdkVersion(context.applicationInfo.packageName)
+ // The offload callbacks are only supported with the new backend,
+ // enabled with target SDK U+.
+ assumeTrue(isAtLeastU() || targetSdkVersion > Build.VERSION_CODES.TIRAMISU)
+ val offloadEngine = TestNsdOffloadEngine()
+ runAsShell(NETWORK_SETTINGS) {
+ nsdManager.registerOffloadEngine(testNetwork1.iface.interfaceName,
+ OffloadEngine.OFFLOAD_TYPE_REPLY.toLong(),
+ OffloadEngine.OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK.toLong(),
+ { it.run() }, offloadEngine)
+ }
+
+ val si = NsdServiceInfo()
+ si.serviceType = "$serviceType,_subtype"
+ si.serviceName = serviceName
+ si.network = testNetwork1.network
+ si.port = 12345
+ val record = NsdRegistrationRecord()
+ nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, record)
+ val addOrUpdateEvent = offloadEngine
+ .expectCallback<TestNsdOffloadEngine.OffloadEvent.AddOrUpdateEvent>()
+ checkOffloadServiceInfo(addOrUpdateEvent.info)
+
+ nsdManager.unregisterService(record)
+ val unregisterEvent = offloadEngine
+ .expectCallback<TestNsdOffloadEngine.OffloadEvent.RemoveEvent>()
+ checkOffloadServiceInfo(unregisterEvent.info)
+
+ runAsShell(NETWORK_SETTINGS) {
+ nsdManager.unregisterOffloadEngine(offloadEngine)
+ }
+ }
+
private fun checkConnectSocketToMdnsd(shouldFail: Boolean) {
val discoveryRecord = NsdDiscoveryRecord()
val localSocket = LocalSocket()
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManagerTests.java b/tests/unit/java/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManagerTests.java
index 8fb7be1..bb59e0d 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManagerTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/ConnectivityMonitorWithConnectivityManagerTests.java
@@ -31,6 +31,7 @@
import android.net.Network;
import android.net.NetworkRequest;
+import com.android.net.module.util.SharedLog;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -49,6 +50,7 @@
@Mock private Context mContext;
@Mock private ConnectivityMonitor.Listener mockListener;
@Mock private ConnectivityManager mConnectivityManager;
+ @Mock private SharedLog sharedLog;
private ConnectivityMonitorWithConnectivityManager monitor;
@@ -57,7 +59,7 @@
MockitoAnnotations.initMocks(this);
doReturn(mConnectivityManager).when(mContext)
.getSystemService(Context.CONNECTIVITY_SERVICE);
- monitor = new ConnectivityMonitorWithConnectivityManager(mContext, mockListener);
+ monitor = new ConnectivityMonitorWithConnectivityManager(mContext, mockListener, sharedLog);
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
index 6a0334f..9b38fea 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAdvertiserTest.kt
@@ -20,6 +20,8 @@
import android.net.LinkAddress
import android.net.Network
import android.net.nsd.NsdServiceInfo
+import android.net.nsd.OffloadEngine
+import android.net.nsd.OffloadServiceInfo
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
@@ -60,6 +62,8 @@
private val TEST_SOCKETKEY_2 = SocketKey(1002 /* interfaceIndex */)
private val TEST_HOSTNAME = arrayOf("Android_test", "local")
private const val TEST_SUBTYPE = "_subtype"
+private val TEST_INTERFACE1 = "test_iface1"
+private val TEST_INTERFACE2 = "test_iface2"
private val SERVICE_1 = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply {
port = 12345
@@ -94,6 +98,24 @@
network = null
}
+private val OFFLOAD_SERVICEINFO = OffloadServiceInfo(
+ OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"),
+ listOf(TEST_SUBTYPE),
+ "Android_test.local",
+ null, /* rawOffloadPacket */
+ 0, /* priority */
+ OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
+)
+
+private val OFFLOAD_SERVICEINFO_NO_SUBTYPE = OffloadServiceInfo(
+ OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"),
+ listOf(),
+ "Android_test.local",
+ null, /* rawOffloadPacket */
+ 0, /* priority */
+ OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
+)
+
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsAdvertiserTest {
@@ -123,6 +145,8 @@
doReturn(true).`when`(mockInterfaceAdvertiser2).isProbing(anyInt())
doReturn(createEmptyNetworkInterface()).`when`(mockSocket1).getInterface()
doReturn(createEmptyNetworkInterface()).`when`(mockSocket2).getInterface()
+ doReturn(TEST_INTERFACE1).`when`(mockInterfaceAdvertiser1).socketInterfaceName
+ doReturn(TEST_INTERFACE2).`when`(mockInterfaceAdvertiser2).socketInterfaceName
}
@After
@@ -160,12 +184,15 @@
)
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
- postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
+ postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
+ verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
postSync { socketCb.onInterfaceDestroyed(TEST_SOCKETKEY_1, mockSocket1) }
verify(mockInterfaceAdvertiser1).destroyNow()
+ postSync { intAdvCbCaptor.value.onDestroyed(mockSocket1) }
+ verify(cb).onOffloadStop(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
}
@Test
@@ -195,14 +222,16 @@
anyInt(), eq(ALL_NETWORKS_SERVICE), eq(TEST_SUBTYPE))
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
- postSync { intAdvCbCaptor1.value.onRegisterServiceSucceeded(
+ postSync { intAdvCbCaptor1.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
+ verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO))
// Need both advertisers to finish probing and call onRegisterServiceSucceeded
verify(cb, never()).onRegisterServiceSucceeded(anyInt(), any())
doReturn(false).`when`(mockInterfaceAdvertiser2).isProbing(SERVICE_ID_1)
- postSync { intAdvCbCaptor2.value.onRegisterServiceSucceeded(
+ postSync { intAdvCbCaptor2.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser2, SERVICE_ID_1) }
+ verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE2), eq(OFFLOAD_SERVICEINFO))
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1),
argThat { it.matches(ALL_NETWORKS_SERVICE) })
@@ -210,6 +239,8 @@
postSync { advertiser.removeService(SERVICE_ID_1) }
verify(mockInterfaceAdvertiser1).removeService(SERVICE_ID_1)
verify(mockInterfaceAdvertiser2).removeService(SERVICE_ID_1)
+ verify(cb).onOffloadStop(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO))
+ verify(cb).onOffloadStop(eq(TEST_INTERFACE2), eq(OFFLOAD_SERVICEINFO))
// Interface advertisers call onDestroyed after sending exit announcements
postSync { intAdvCbCaptor1.value.onDestroyed(mockSocket1) }
@@ -285,12 +316,12 @@
argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null))
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
- postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
+ postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_2)
- postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
+ postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_2) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_2),
argThat { it.matches(expectedRenamed) })
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
index 7c6cb3e..12faa50 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
@@ -21,6 +21,7 @@
import android.os.HandlerThread
import android.os.SystemClock
import com.android.internal.util.HexDump
+import com.android.net.module.util.SharedLog
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo
import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress
@@ -52,6 +53,7 @@
private val thread = HandlerThread(MdnsAnnouncerTest::class.simpleName)
private val socket = mock(MdnsInterfaceSocket::class.java)
+ private val sharedLog = mock(SharedLog::class.java)
private val buffer = ByteArray(1500)
@Before
@@ -80,11 +82,11 @@
@Test
fun testAnnounce() {
- val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
+ val replySender = MdnsReplySender( thread.looper, socket, buffer, sharedLog)
@Suppress("UNCHECKED_CAST")
val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java)
as MdnsPacketRepeater.PacketRepeaterCallback<BaseAnnouncementInfo>
- val announcer = MdnsAnnouncer("testiface", thread.looper, replySender, cb)
+ val announcer = MdnsAnnouncer(thread.looper, replySender, cb, sharedLog)
/*
The expected packet replicates records announced when registering a service, as observed in
the legacy mDNS implementation (some ordering differs to be more readable).
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
index dd458b8..c19747e 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
@@ -108,9 +108,9 @@
doReturn(repository).`when`(deps).makeRecordRepository(any(),
eq(TEST_HOSTNAME)
)
- doReturn(replySender).`when`(deps).makeReplySender(anyString(), any(), any(), any())
- doReturn(announcer).`when`(deps).makeMdnsAnnouncer(anyString(), any(), any(), any())
- doReturn(prober).`when`(deps).makeMdnsProber(anyString(), any(), any(), any())
+ doReturn(replySender).`when`(deps).makeReplySender(anyString(), any(), any(), any(), any())
+ doReturn(announcer).`when`(deps).makeMdnsAnnouncer(anyString(), any(), any(), any(), any())
+ doReturn(prober).`when`(deps).makeMdnsProber(anyString(), any(), any(), any(), any())
val knownServices = mutableSetOf<Int>()
doAnswer { inv ->
@@ -132,8 +132,8 @@
advertiser.start()
verify(socket).addPacketHandler(packetHandlerCaptor.capture())
- verify(deps).makeMdnsProber(any(), any(), any(), probeCbCaptor.capture())
- verify(deps).makeMdnsAnnouncer(any(), any(), any(), announceCbCaptor.capture())
+ verify(deps).makeMdnsProber(any(), any(), any(), probeCbCaptor.capture(), any())
+ verify(deps).makeMdnsAnnouncer(any(), any(), any(), announceCbCaptor.capture(), any())
}
@After
@@ -150,7 +150,7 @@
0L /* initialDelayMs */)
thread.waitForIdle(TIMEOUT_MS)
- verify(cb).onRegisterServiceSucceeded(advertiser, TEST_SERVICE_ID_1)
+ verify(cb).onServiceProbingSucceeded(advertiser, TEST_SERVICE_ID_1)
// Remove the service: expect exit announcements
val testExitInfo = mock(ExitAnnouncementInfo::class.java)
@@ -256,7 +256,7 @@
val mockProbingInfo = mock(ProbingInfo::class.java)
doReturn(mockProbingInfo).`when`(repository).setServiceProbing(TEST_SERVICE_ID_1)
- advertiser.restartProbingForConflict(TEST_SERVICE_ID_1)
+ advertiser.maybeRestartProbingForConflict(TEST_SERVICE_ID_1)
verify(prober).restartForConflict(mockProbingInfo)
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
index 29de272..3701b0c 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClientTest.java
@@ -36,6 +36,7 @@
import android.os.HandlerThread;
import com.android.net.module.util.HexDump;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.MdnsSocketClientBase.SocketCreationCallback;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -66,6 +67,7 @@
@Mock private MdnsServiceBrowserListener mListener;
@Mock private MdnsSocketClientBase.Callback mCallback;
@Mock private SocketCreationCallback mSocketCreationCallback;
+ @Mock private SharedLog mSharedLog;
private MdnsMultinetworkSocketClient mSocketClient;
private Handler mHandler;
private SocketKey mSocketKey;
@@ -78,7 +80,7 @@
thread.start();
mHandler = new Handler(thread.getLooper());
mSocketKey = new SocketKey(1000 /* interfaceIndex */);
- mSocketClient = new MdnsMultinetworkSocketClient(thread.getLooper(), mProvider);
+ mSocketClient = new MdnsMultinetworkSocketClient(thread.getLooper(), mProvider, mSharedLog);
mHandler.post(() -> mSocketClient.setCallback(mCallback));
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
index 0a8d78d..5ca4dd6 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsProberTest.kt
@@ -21,6 +21,7 @@
import android.os.HandlerThread
import android.os.Looper
import com.android.internal.util.HexDump
+import com.android.net.module.util.SharedLog
import com.android.server.connectivity.mdns.MdnsProber.ProbingInfo
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
@@ -55,6 +56,7 @@
class MdnsProberTest {
private val thread = HandlerThread(MdnsProberTest::class.simpleName)
private val socket = mock(MdnsInterfaceSocket::class.java)
+ private val sharedLog = mock(SharedLog::class.java)
@Suppress("UNCHECKED_CAST")
private val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java)
as MdnsPacketRepeater.PacketRepeaterCallback<ProbingInfo>
@@ -82,8 +84,9 @@
private class TestProber(
looper: Looper,
replySender: MdnsReplySender,
- cb: PacketRepeaterCallback<ProbingInfo>
- ) : MdnsProber("testiface", looper, replySender, cb) {
+ cb: PacketRepeaterCallback<ProbingInfo>,
+ sharedLog: SharedLog
+ ) : MdnsProber(looper, replySender, cb, sharedLog) {
override fun getInitialDelay() = 0L
}
@@ -116,8 +119,8 @@
@Test
fun testProbe() {
- val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
- val prober = TestProber(thread.looper, replySender, cb)
+ val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(
listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890)))
prober.startProbing(probeInfo)
@@ -140,8 +143,8 @@
@Test
fun testProbeMultipleRecords() {
- val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
- val prober = TestProber(thread.looper, replySender, cb)
+ val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(listOf(
makeServiceRecord(TEST_SERVICE_NAME_1, 37890),
makeServiceRecord(TEST_SERVICE_NAME_2, 37891),
@@ -178,8 +181,8 @@
@Test
fun testStopProbing() {
- val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)
- val prober = TestProber(thread.looper, replySender, cb)
+ val replySender = MdnsReplySender(thread.looper, socket, buffer, sharedLog)
+ val prober = TestProber(thread.looper, replySender, cb, sharedLog)
val probeInfo = TestProbeInfo(
listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890)),
// delayMs is the delay between each probe, so does not apply to the first one
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
index 69efc61..74f1c37 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
@@ -39,6 +39,7 @@
import android.text.format.DateUtils;
import com.android.net.module.util.HexDump;
+import com.android.net.module.util.SharedLog;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -74,6 +75,7 @@
@Mock private MdnsSocket mockUnicastSocket;
@Mock private MulticastLock mockMulticastLock;
@Mock private MdnsSocketClient.Callback mockCallback;
+ @Mock private SharedLog sharedLog;
private MdnsSocketClient mdnsClient;
@@ -84,9 +86,9 @@
when(mockWifiManager.createMulticastLock(ArgumentMatchers.anyString()))
.thenReturn(mockMulticastLock);
- mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock) {
+ mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock, sharedLog) {
@Override
- MdnsSocket createMdnsSocket(int port) throws IOException {
+ MdnsSocket createMdnsSocket(int port, SharedLog sharedLog) throws IOException {
if (port == MdnsConstants.MDNS_PORT) {
return mockMulticastSocket;
}
@@ -513,9 +515,9 @@
//MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(true);
when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
- mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock) {
+ mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock, sharedLog) {
@Override
- MdnsSocket createMdnsSocket(int port) {
+ MdnsSocket createMdnsSocket(int port, SharedLog sharedLog) {
if (port == MdnsConstants.MDNS_PORT) {
return mockMulticastSocket;
}
@@ -536,9 +538,9 @@
//MdnsConfigsFlagsImpl.allowNetworkInterfaceIndexPropagation.override(false);
when(mockMulticastSocket.getInterfaceIndex()).thenReturn(21);
- mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock) {
+ mdnsClient = new MdnsSocketClient(mContext, mockMulticastLock, sharedLog) {
@Override
- MdnsSocket createMdnsSocket(int port) {
+ MdnsSocket createMdnsSocket(int port, SharedLog sharedLog) {
if (port == MdnsConstants.MDNS_PORT) {
return mockMulticastSocket;
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
index e971de7..c0b74e1 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -152,11 +152,11 @@
.getNetworkInterfaceByName(WIFI_P2P_IFACE_NAME);
doReturn(mTetheredIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TETHERED_IFACE_NAME);
doReturn(mock(MdnsInterfaceSocket.class))
- .when(mDeps).createMdnsInterfaceSocket(any(), anyInt(), any(), any());
+ .when(mDeps).createMdnsInterfaceSocket(any(), anyInt(), any(), any(), any());
doReturn(TETHERED_IFACE_IDX).when(mDeps).getNetworkInterfaceIndexByName(
- TETHERED_IFACE_NAME);
+ eq(TETHERED_IFACE_NAME), any());
doReturn(789).when(mDeps).getNetworkInterfaceIndexByName(
- WIFI_P2P_IFACE_NAME);
+ eq(WIFI_P2P_IFACE_NAME), any());
final HandlerThread thread = new HandlerThread("MdnsSocketProviderTest");
thread.start();
mHandler = new Handler(thread.getLooper());
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
index 73dbd38..5809684 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketTests.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.android.net.module.util.SharedLog;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -50,6 +51,7 @@
@Mock private NetworkInterfaceWrapper mockNetworkInterfaceWrapper;
@Mock private MulticastSocket mockMulticastSocket;
@Mock private MulticastNetworkInterfaceProvider mockMulticastNetworkInterfaceProvider;
+ @Mock private SharedLog sharedLog;
private SocketAddress socketIPv4Address;
private SocketAddress socketIPv6Address;
@@ -75,7 +77,8 @@
@Test
public void mdnsSocket_basicFunctionality() throws IOException {
- mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
+ mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket,
+ sharedLog);
mdnsSocket.send(datagramPacket);
verify(mockMulticastSocket).setNetworkInterface(networkInterface);
verify(mockMulticastSocket).send(datagramPacket);
@@ -101,7 +104,8 @@
when(mockMulticastNetworkInterfaceProvider.getMulticastNetworkInterfaces())
.thenReturn(Collections.singletonList(mockNetworkInterfaceWrapper));
- mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
+ mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket,
+ sharedLog);
when(mockMulticastNetworkInterfaceProvider.isOnIpV6OnlyNetwork(
Collections.singletonList(mockNetworkInterfaceWrapper)))
@@ -125,7 +129,8 @@
when(mockMulticastNetworkInterfaceProvider.getMulticastNetworkInterfaces())
.thenReturn(Collections.singletonList(mockNetworkInterfaceWrapper));
- mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket);
+ mdnsSocket = new MdnsSocket(mockMulticastNetworkInterfaceProvider, mockMulticastSocket,
+ sharedLog);
when(mockMulticastNetworkInterfaceProvider.isOnIpV6OnlyNetwork(
Collections.singletonList(mockNetworkInterfaceWrapper)))
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProviderTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProviderTests.java
index 2268dfe..af233c9 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProviderTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProviderTests.java
@@ -30,6 +30,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.net.module.util.SharedLog;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -65,6 +66,8 @@
@Mock private NetworkInterfaceWrapper multicastInterfaceOne;
@Mock private NetworkInterfaceWrapper multicastInterfaceTwo;
+ @Mock private SharedLog sharedLog;
+
private final List<NetworkInterfaceWrapper> networkInterfaces = new ArrayList<>();
private MulticastNetworkInterfaceProvider provider;
private Context context;
@@ -156,7 +159,7 @@
false /* isIpv6 */);
provider =
- new MulticastNetworkInterfaceProvider(context) {
+ new MulticastNetworkInterfaceProvider(context, sharedLog) {
@Override
List<NetworkInterfaceWrapper> getNetworkInterfaces() {
return networkInterfaces;