Snap for 12316586 from 01092368c71b2fd7a370ad279b6e0311dfc2ee12 to mainline-cellbroadcast-release Change-Id: I5badfc2fdc69af635254c56bb583125eab8f3f8e
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp index a5d7230..004ec09 100644 --- a/common/networkstackclient/Android.bp +++ b/common/networkstackclient/Android.bp
@@ -97,8 +97,13 @@ version: "10", imports: [], }, + { + version: "11", + imports: [], + }, ], + frozen: true, } @@ -167,7 +172,7 @@ enabled: false, }, }, - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], // TODO: have tethering depend on networkstack-client and set visibility to private visibility: [ "//system/tools/aidl/build", @@ -178,39 +183,43 @@ // Remove old networkstack aidl interface version info that is no longer used. { version: "13", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "14", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "15", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "16", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "17", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "18", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "19", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "20", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], }, { version: "21", - imports: ["ipmemorystore-aidl-interfaces-V10"], + imports: ["ipmemorystore-aidl-interfaces-V11"], + }, + { + version: "22", + imports: ["ipmemorystore-aidl-interfaces-V11"], }, ], @@ -222,8 +231,8 @@ sdk_version: "system_current", min_sdk_version: "30", static_libs: [ - "ipmemorystore-aidl-interfaces-V10-java", - "networkstack-aidl-interfaces-V21-java", + "ipmemorystore-aidl-interfaces-V11-java", + "networkstack-aidl-interfaces-V22-java", ], visibility: ["//packages/modules/NetworkStack:__subpackages__"], apex_available: [
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/.hash b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/.hash new file mode 100644 index 0000000..bd4b743 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/.hash
@@ -0,0 +1 @@ +b24ee617afb80799cb35b6241f5847d786c649f3
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStore.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStore.aidl new file mode 100644 index 0000000..e2c94a2 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStore.aidl
@@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface IIpMemoryStore { + oneway void storeNetworkAttributes(String l2Key, in android.net.ipmemorystore.NetworkAttributesParcelable attributes, android.net.ipmemorystore.IOnStatusListener listener); + oneway void storeBlob(String l2Key, String clientId, String name, in android.net.ipmemorystore.Blob data, android.net.ipmemorystore.IOnStatusListener listener); + oneway void findL2Key(in android.net.ipmemorystore.NetworkAttributesParcelable attributes, android.net.ipmemorystore.IOnL2KeyResponseListener listener); + oneway void isSameNetwork(String l2Key1, String l2Key2, android.net.ipmemorystore.IOnSameL3NetworkResponseListener listener); + oneway void retrieveNetworkAttributes(String l2Key, android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener listener); + oneway void retrieveBlob(String l2Key, String clientId, String name, android.net.ipmemorystore.IOnBlobRetrievedListener listener); + oneway void factoryReset(); + oneway void delete(String l2Key, boolean needWipe, android.net.ipmemorystore.IOnStatusAndCountListener listener); + oneway void deleteCluster(String cluster, boolean needWipe, android.net.ipmemorystore.IOnStatusAndCountListener listener); + oneway void storeNetworkEvent(String cluster, long timestamp, long expiry, int eventType, android.net.ipmemorystore.IOnStatusListener listener); + oneway void retrieveNetworkEventCount(String cluster, in long[] sinceTimes, in int[] eventTypes, android.net.ipmemorystore.IOnNetworkEventCountRetrievedListener listener); + const int NETWORK_EVENT_NUD_FAILURE_ROAM = 0; + const int NETWORK_EVENT_NUD_FAILURE_CONFIRM = 1; + const int NETWORK_EVENT_NUD_FAILURE_ORGANIC = 2; + const int NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED = 3; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStoreCallbacks.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStoreCallbacks.aidl new file mode 100644 index 0000000..7dbbc98 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/IIpMemoryStoreCallbacks.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface IIpMemoryStoreCallbacks { + oneway void onIpMemoryStoreFetched(in android.net.IIpMemoryStore ipMemoryStore); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/Blob.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/Blob.aidl new file mode 100644 index 0000000..4300c83 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/Blob.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +parcelable Blob { + byte[] data; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl new file mode 100644 index 0000000..3a263e2 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnBlobRetrievedListener { + oneway void onBlobRetrieved(in android.net.ipmemorystore.StatusParcelable status, in String l2Key, in String name, in android.net.ipmemorystore.Blob data); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl new file mode 100644 index 0000000..c663ccf --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnL2KeyResponseListener { + oneway void onL2KeyResponse(in android.net.ipmemorystore.StatusParcelable status, in String l2Key); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl new file mode 100644 index 0000000..3740e15 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnNetworkAttributesRetrievedListener { + oneway void onNetworkAttributesRetrieved(in android.net.ipmemorystore.StatusParcelable status, in String l2Key, in android.net.ipmemorystore.NetworkAttributesParcelable attributes); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl new file mode 100644 index 0000000..29d7781 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnNetworkEventCountRetrievedListener { + oneway void onNetworkEventCountRetrieved(in android.net.ipmemorystore.StatusParcelable status, in int[] counts); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl new file mode 100644 index 0000000..9d87fbb --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnSameL3NetworkResponseListener { + oneway void onSameL3NetworkResponse(in android.net.ipmemorystore.StatusParcelable status, in android.net.ipmemorystore.SameL3NetworkResponseParcelable response); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusAndCountListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusAndCountListener.aidl new file mode 100644 index 0000000..1e6a41c --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusAndCountListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnStatusAndCountListener { + oneway void onComplete(in android.net.ipmemorystore.StatusParcelable status, int count); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusListener.aidl new file mode 100644 index 0000000..dccdf27 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/IOnStatusListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnStatusListener { + oneway void onComplete(in android.net.ipmemorystore.StatusParcelable status); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/NetworkAttributesParcelable.aidl new file mode 100644 index 0000000..85af005 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 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. + */// Blob[] is used to represent an array of byte[], as structured AIDL does not support arrays +// of arrays. +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +@JavaDerive(toString=true) +parcelable NetworkAttributesParcelable { + byte[] assignedV4Address; + long assignedV4AddressExpiry; + String cluster; + android.net.ipmemorystore.Blob[] dnsAddresses; + int mtu; + @nullable android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirkParcelable ipv6ProvisioningLossQuirk; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl new file mode 100644 index 0000000..377a3ec --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +@JavaDerive(toString=true) +parcelable SameL3NetworkResponseParcelable { + String l2Key1; + String l2Key2; + float confidence; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/StatusParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/StatusParcelable.aidl new file mode 100644 index 0000000..59b96cd --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/ipmemorystore/StatusParcelable.aidl
@@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +@JavaDerive(toString=true) +parcelable StatusParcelable { + int resultCode; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl new file mode 100644 index 0000000..c01564b --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/11/android/net/networkstack/aidl/quirks/IPv6ProvisioningLossQuirkParcelable.aidl
@@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.networkstack.aidl.quirks; +@JavaDerive(toString=true) +parcelable IPv6ProvisioningLossQuirkParcelable { + int detectionCount; + long quirkExpiry; +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl index 048e84c..e2c94a2 100644 --- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/IIpMemoryStore.aidl
@@ -43,4 +43,10 @@ oneway void factoryReset(); oneway void delete(String l2Key, boolean needWipe, android.net.ipmemorystore.IOnStatusAndCountListener listener); oneway void deleteCluster(String cluster, boolean needWipe, android.net.ipmemorystore.IOnStatusAndCountListener listener); + oneway void storeNetworkEvent(String cluster, long timestamp, long expiry, int eventType, android.net.ipmemorystore.IOnStatusListener listener); + oneway void retrieveNetworkEventCount(String cluster, in long[] sinceTimes, in int[] eventTypes, android.net.ipmemorystore.IOnNetworkEventCountRetrievedListener listener); + const int NETWORK_EVENT_NUD_FAILURE_ROAM = 0; + const int NETWORK_EVENT_NUD_FAILURE_CONFIRM = 1; + const int NETWORK_EVENT_NUD_FAILURE_ORGANIC = 2; + const int NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED = 3; }
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl new file mode 100644 index 0000000..29d7781 --- /dev/null +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ipmemorystore; +/* @hide */ +interface IOnNetworkEventCountRetrievedListener { + oneway void onNetworkEventCountRetrieved(in android.net.ipmemorystore.StatusParcelable status, in int[] counts); +}
diff --git a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl index 227785d..85af005 100644 --- a/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl +++ b/common/networkstackclient/aidl_api/ipmemorystore-aidl-interfaces/current/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -12,7 +12,8 @@ * 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. - */ + */// Blob[] is used to represent an array of byte[], as structured AIDL does not support arrays +// of arrays. /////////////////////////////////////////////////////////////////////////////// // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // ///////////////////////////////////////////////////////////////////////////////
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/.hash b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/.hash new file mode 100644 index 0000000..c5e7453 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/.hash
@@ -0,0 +1 @@ +653a7f7fd2390682f0c3739b4d82d9477d1d79f9
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DataStallReportParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DataStallReportParcelable.aidl new file mode 100644 index 0000000..771deda --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DataStallReportParcelable.aidl
@@ -0,0 +1,42 @@ +/** + * Copyright (c) 2020, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable DataStallReportParcelable { + long timestampMillis = 0; + int detectionMethod = 1; + int tcpPacketFailRate = 2; + int tcpMetricsCollectionPeriodMillis = 3; + int dnsConsecutiveTimeouts = 4; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DhcpResultsParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DhcpResultsParcelable.aidl new file mode 100644 index 0000000..31f2194 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/DhcpResultsParcelable.aidl
@@ -0,0 +1,44 @@ +/** + * Copyright (c) 2019, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable DhcpResultsParcelable { + android.net.StaticIpConfiguration baseConfiguration; + int leaseDuration; + int mtu; + String serverAddress; + String vendorInfo; + @nullable String serverHostName; + @nullable String captivePortalApiUrl; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitor.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitor.aidl new file mode 100644 index 0000000..fb13c0c --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitor.aidl
@@ -0,0 +1,60 @@ +/** + * Copyright (c) 2018, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetworkMonitor { + oneway void start(); + oneway void launchCaptivePortalApp(); + oneway void notifyCaptivePortalAppFinished(int response); + oneway void setAcceptPartialConnectivity(); + oneway void forceReevaluation(int uid); + oneway void notifyPrivateDnsChanged(in android.net.PrivateDnsConfigParcel config); + oneway void notifyDnsResponse(int returnCode); + oneway void notifyNetworkConnected(in android.net.LinkProperties lp, in android.net.NetworkCapabilities nc); + oneway void notifyNetworkDisconnected(); + oneway void notifyLinkPropertiesChanged(in android.net.LinkProperties lp); + oneway void notifyNetworkCapabilitiesChanged(in android.net.NetworkCapabilities nc); + oneway void notifyNetworkConnectedParcel(in android.net.networkstack.aidl.NetworkMonitorParameters params); + const int NETWORK_TEST_RESULT_VALID = 0; + const int NETWORK_TEST_RESULT_INVALID = 1; + const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2; + const int NETWORK_VALIDATION_RESULT_VALID = 0x01; + const int NETWORK_VALIDATION_RESULT_PARTIAL = 0x02; + const int NETWORK_VALIDATION_RESULT_SKIPPED = 0x04; + const int NETWORK_VALIDATION_PROBE_DNS = 0x04; + const int NETWORK_VALIDATION_PROBE_HTTP = 0x08; + const int NETWORK_VALIDATION_PROBE_HTTPS = 0x10; + const int NETWORK_VALIDATION_PROBE_FALLBACK = 0x20; + const int NETWORK_VALIDATION_PROBE_PRIVDNS = 0x40; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitorCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitorCallbacks.aidl new file mode 100644 index 0000000..36eda8e --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkMonitorCallbacks.aidl
@@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetworkMonitorCallbacks { + oneway void onNetworkMonitorCreated(in android.net.INetworkMonitor networkMonitor) = 0; + oneway void notifyNetworkTested(int testResult, @nullable String redirectUrl) = 1; + oneway void notifyPrivateDnsConfigResolved(in android.net.PrivateDnsConfigParcel config) = 2; + oneway void showProvisioningNotification(String action, String packageName) = 3; + oneway void hideProvisioningNotification() = 4; + oneway void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) = 5; + oneway void notifyNetworkTestedWithExtras(in android.net.NetworkTestResultParcelable result) = 6; + oneway void notifyDataStallSuspected(in android.net.DataStallReportParcelable report) = 7; + oneway void notifyCaptivePortalDataChanged(in android.net.CaptivePortalData data) = 8; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackConnector.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackConnector.aidl new file mode 100644 index 0000000..8120ffc --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackConnector.aidl
@@ -0,0 +1,42 @@ +/** + * Copyright (c) 2018, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetworkStackConnector { + oneway void makeDhcpServer(in String ifName, in android.net.dhcp.DhcpServingParamsParcel params, in android.net.dhcp.IDhcpServerCallbacks cb); + oneway void makeNetworkMonitor(in android.net.Network network, String name, in android.net.INetworkMonitorCallbacks cb); + oneway void makeIpClient(in String ifName, in android.net.ip.IIpClientCallbacks callbacks); + oneway void fetchIpMemoryStore(in android.net.IIpMemoryStoreCallbacks cb); + oneway void allowTestUid(int uid, in android.net.INetworkStackStatusCallback cb); +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackStatusCallback.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackStatusCallback.aidl new file mode 100644 index 0000000..0b6b778 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/INetworkStackStatusCallback.aidl
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +/* @hide */ +interface INetworkStackStatusCallback { + oneway void onStatusAvailable(int statusCode); +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InformationElementParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InformationElementParcelable.aidl new file mode 100644 index 0000000..6103774 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InformationElementParcelable.aidl
@@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable InformationElementParcelable { + int id; + byte[] payload; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InitialConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InitialConfigurationParcelable.aidl new file mode 100644 index 0000000..6a597e6 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/InitialConfigurationParcelable.aidl
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable InitialConfigurationParcelable { + android.net.LinkAddress[] ipAddresses; + android.net.IpPrefix[] directlyConnectedRoutes; + String[] dnsServers; + String gateway; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2InformationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2InformationParcelable.aidl new file mode 100644 index 0000000..83796ee --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2InformationParcelable.aidl
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable Layer2InformationParcelable { + String l2Key; + String cluster; + android.net.MacAddress bssid; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2PacketParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2PacketParcelable.aidl new file mode 100644 index 0000000..4b3fff5 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/Layer2PacketParcelable.aidl
@@ -0,0 +1,39 @@ +/** + * Copyright (c) 2019, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable Layer2PacketParcelable { + android.net.MacAddress dstMacAddress; + byte[] payload; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NattKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NattKeepalivePacketDataParcelable.aidl new file mode 100644 index 0000000..18cf954 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable NattKeepalivePacketDataParcelable { + byte[] srcAddress; + int srcPort; + byte[] dstAddress; + int dstPort; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NetworkTestResultParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NetworkTestResultParcelable.aidl new file mode 100644 index 0000000..4d6d5a2 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/NetworkTestResultParcelable.aidl
@@ -0,0 +1,42 @@ +/** + * Copyright (c) 2020, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable NetworkTestResultParcelable { + long timestampMillis; + int result; + int probesSucceeded; + int probesAttempted; + String redirectUrl; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/PrivateDnsConfigParcel.aidl new file mode 100644 index 0000000..b624ee4 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/PrivateDnsConfigParcel.aidl
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(equals=true, toString=true) +parcelable PrivateDnsConfigParcel { + String hostname; + String[] ips; + int privateDnsMode = (-1) /* -1 */; + String dohName = ""; + String[] dohIps = {}; + String dohPath = ""; + int dohPort = (-1) /* -1 */; + boolean ddrEnabled = false; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ProvisioningConfigurationParcelable.aidl new file mode 100644 index 0000000..0ce91f0 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ProvisioningConfigurationParcelable.aidl
@@ -0,0 +1,65 @@ +/* +** +** Copyright (C) 2019 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. +*/ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable ProvisioningConfigurationParcelable { + /** + * @deprecated use ipv4ProvisioningMode instead. + */ + boolean enableIPv4; + /** + * @deprecated use ipv6ProvisioningMode instead. + */ + boolean enableIPv6; + boolean usingMultinetworkPolicyTracker; + boolean usingIpReachabilityMonitor; + int requestedPreDhcpActionMs; + android.net.InitialConfigurationParcelable initialConfig; + android.net.StaticIpConfiguration staticIpConfig; + android.net.apf.ApfCapabilities apfCapabilities; + int provisioningTimeoutMs; + int ipv6AddrGenMode; + android.net.Network network; + String displayName; + boolean enablePreconnection; + @nullable android.net.ScanResultInfoParcelable scanResultInfo; + @nullable android.net.Layer2InformationParcelable layer2Info; + @nullable List<android.net.networkstack.aidl.dhcp.DhcpOption> options; + int ipv4ProvisioningMode; + int ipv6ProvisioningMode; + boolean uniqueEui64AddressesOnly; + int creatorUid; + int hostnameSetting; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ScanResultInfoParcelable.aidl new file mode 100644 index 0000000..94fc27f --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ScanResultInfoParcelable.aidl
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable ScanResultInfoParcelable { + String ssid; + String bssid; + android.net.InformationElementParcelable[] informationElements; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/TcpKeepalivePacketDataParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/TcpKeepalivePacketDataParcelable.aidl new file mode 100644 index 0000000..0e1c21c --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net; +@JavaDerive(toString=true) +parcelable TcpKeepalivePacketDataParcelable { + byte[] srcAddress; + int srcPort; + byte[] dstAddress; + int dstPort; + int seq; + int ack; + int rcvWnd; + int rcvWndScale; + int tos; + int ttl; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpLeaseParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpLeaseParcelable.aidl new file mode 100644 index 0000000..3cd8860 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpLeaseParcelable.aidl
@@ -0,0 +1,43 @@ +/** + * Copyright (c) 2020, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.dhcp; +@JavaDerive(toString=true) +parcelable DhcpLeaseParcelable { + byte[] clientId; + byte[] hwAddr; + int netAddr; + int prefixLength; + long expTime; + String hostname; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpServingParamsParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpServingParamsParcel.aidl new file mode 100644 index 0000000..7997936 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,49 @@ +/** + * + * Copyright (C) 2018 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.dhcp; +@JavaDerive(toString=true) +parcelable DhcpServingParamsParcel { + int serverAddr; + int serverAddrPrefixLength; + int[] defaultRouters; + int[] dnsServers; + int[] excludedAddrs; + long dhcpLeaseTimeSecs; + int linkMtu; + boolean metered; + int singleClientAddr = 0; + boolean changePrefixOnDecline = false; + int leasesSubnetPrefixLength = 0; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpEventCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpEventCallbacks.aidl new file mode 100644 index 0000000..9312f47 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpEventCallbacks.aidl
@@ -0,0 +1,38 @@ +/** + * Copyright (c) 2020, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.dhcp; +interface IDhcpEventCallbacks { + oneway void onLeasesChanged(in List<android.net.dhcp.DhcpLeaseParcelable> newLeases); + oneway void onNewPrefixRequest(in android.net.IpPrefix currentPrefix); +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServer.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServer.aidl new file mode 100644 index 0000000..1109f35 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServer.aidl
@@ -0,0 +1,45 @@ +/** + * Copyright (c) 2018, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.dhcp; +/* @hide */ +interface IDhcpServer { + oneway void start(in android.net.INetworkStackStatusCallback cb) = 0; + oneway void startWithCallbacks(in android.net.INetworkStackStatusCallback statusCb, in android.net.dhcp.IDhcpEventCallbacks eventCb) = 3; + oneway void updateParams(in android.net.dhcp.DhcpServingParamsParcel params, in android.net.INetworkStackStatusCallback cb) = 1; + oneway void stop(in android.net.INetworkStackStatusCallback cb) = 2; + const int STATUS_UNKNOWN = 0; + const int STATUS_SUCCESS = 1; + const int STATUS_INVALID_ARGUMENT = 2; + const int STATUS_UNKNOWN_ERROR = 3; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServerCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServerCallbacks.aidl new file mode 100644 index 0000000..ab8577c --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -0,0 +1,38 @@ +/** + * Copyright (c) 2018, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.dhcp; +/* @hide */ +interface IDhcpServerCallbacks { + oneway void onDhcpServerCreated(int statusCode, in android.net.dhcp.IDhcpServer server); +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClient.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClient.aidl new file mode 100644 index 0000000..87de4a6 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClient.aidl
@@ -0,0 +1,62 @@ +/** + * Copyright (c) 2019, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ip; +/* @hide */ +interface IIpClient { + oneway void completedPreDhcpAction(); + oneway void confirmConfiguration(); + oneway void readPacketFilterComplete(in byte[] data); + oneway void shutdown(); + oneway void startProvisioning(in android.net.ProvisioningConfigurationParcelable req); + oneway void stop(); + oneway void setTcpBufferSizes(in String tcpBufferSizes); + oneway void setHttpProxy(in android.net.ProxyInfo proxyInfo); + oneway void setMulticastFilter(boolean enabled); + oneway void addKeepalivePacketFilter(int slot, in android.net.TcpKeepalivePacketDataParcelable pkt); + oneway void removeKeepalivePacketFilter(int slot); + oneway void setL2KeyAndGroupHint(in String l2Key, in String cluster); + oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt); + oneway void notifyPreconnectionComplete(boolean success); + oneway void updateLayer2Information(in android.net.Layer2InformationParcelable info); + oneway void updateApfCapabilities(in android.net.apf.ApfCapabilities apfCapabilities); + const int PROV_IPV4_DISABLED = 0x00; + const int PROV_IPV4_STATIC = 0x01; + const int PROV_IPV4_DHCP = 0x02; + const int PROV_IPV6_DISABLED = 0x00; + const int PROV_IPV6_SLAAC = 0x01; + const int PROV_IPV6_LINKLOCAL = 0x02; + const int HOSTNAME_SETTING_UNSET = 0x00; + const int HOSTNAME_SETTING_SEND = 0x01; + const int HOSTNAME_SETTING_DO_NOT_SEND = 0x02; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClientCallbacks.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClientCallbacks.aidl new file mode 100644 index 0000000..9d36419 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/ip/IIpClientCallbacks.aidl
@@ -0,0 +1,54 @@ +/** + * Copyright (c) 2019, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.ip; +/* @hide */ +interface IIpClientCallbacks { + oneway void onIpClientCreated(in android.net.ip.IIpClient ipClient); + oneway void onPreDhcpAction(); + oneway void onPostDhcpAction(); + oneway void onNewDhcpResults(in android.net.DhcpResultsParcelable dhcpResults); + oneway void onProvisioningSuccess(in android.net.LinkProperties newLp); + oneway void onProvisioningFailure(in android.net.LinkProperties newLp); + oneway void onLinkPropertiesChange(in android.net.LinkProperties newLp); + oneway void onReachabilityLost(in String logMsg); + oneway void onQuit(); + oneway void installPacketFilter(in byte[] filter); + oneway void startReadPacketFilter(); + oneway void setFallbackMulticastFilter(boolean enabled); + oneway void setNeighborDiscoveryOffload(boolean enable); + oneway void onPreconnectionStart(in List<android.net.Layer2PacketParcelable> packets); + oneway void onReachabilityFailure(in android.net.networkstack.aidl.ip.ReachabilityLossInfoParcelable lossInfo); + oneway void setMaxDtimMultiplier(int multiplier); + const int DTIM_MULTIPLIER_RESET = 0; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/NetworkMonitorParameters.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/NetworkMonitorParameters.aidl new file mode 100644 index 0000000..2ab9db0 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/NetworkMonitorParameters.aidl
@@ -0,0 +1,41 @@ +/** + * + * Copyright (C) 2022 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.networkstack.aidl; +@JavaDerive(equals=true, toString=true) +parcelable NetworkMonitorParameters { + android.net.NetworkAgentConfig networkAgentConfig; + android.net.NetworkCapabilities networkCapabilities; + android.net.LinkProperties linkProperties; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/dhcp/DhcpOption.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/dhcp/DhcpOption.aidl new file mode 100644 index 0000000..eea3e0d --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/dhcp/DhcpOption.aidl
@@ -0,0 +1,39 @@ +/** + * Copyright (c) 2020, 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 perNmissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.networkstack.aidl.dhcp; +@JavaDerive(toString=true) +parcelable DhcpOption { + byte type; + @nullable byte[] value; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossInfoParcelable.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossInfoParcelable.aidl new file mode 100644 index 0000000..bb88434 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossInfoParcelable.aidl
@@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.networkstack.aidl.ip; +@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable +parcelable ReachabilityLossInfoParcelable { + String message; + android.net.networkstack.aidl.ip.ReachabilityLossReason reason; +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossReason.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossReason.aidl new file mode 100644 index 0000000..f9bb3c4 --- /dev/null +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/22/android/net/networkstack/aidl/ip/ReachabilityLossReason.aidl
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.net.networkstack.aidl.ip; +@Backing(type="int") +enum ReachabilityLossReason { + ROAM, + CONFIRM, + ORGANIC, +}
diff --git a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl index ab62fe7..b624ee4 100644 --- a/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl +++ b/common/networkstackclient/aidl_api/networkstack-aidl-interfaces/current/android/net/PrivateDnsConfigParcel.aidl
@@ -41,4 +41,5 @@ String[] dohIps = {}; String dohPath = ""; int dohPort = (-1) /* -1 */; + boolean ddrEnabled = false; }
diff --git a/common/networkstackclient/src/android/net/IIpMemoryStore.aidl b/common/networkstackclient/src/android/net/IIpMemoryStore.aidl index 3bb58bf..e294f54 100644 --- a/common/networkstackclient/src/android/net/IIpMemoryStore.aidl +++ b/common/networkstackclient/src/android/net/IIpMemoryStore.aidl
@@ -21,6 +21,7 @@ import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.IOnNetworkEventCountRetrievedListener; import android.net.ipmemorystore.IOnSameL3NetworkResponseListener; import android.net.ipmemorystore.IOnStatusAndCountListener; import android.net.ipmemorystore.IOnStatusListener; @@ -152,4 +153,48 @@ * @return (through the listener) A status to indicate success and the number of deleted records */ void deleteCluster(String cluster, boolean needWipe, IOnStatusAndCountListener listener); + + /** + * The network event types related to Neighbor Unreachability Detection(NUD) probe failure + * including probe fails due to L2 roam, low Wi-Fi RSSI checks, periodic kernel organic checks, + * or a neighbor's MAC address changing during a probe. + */ + const int NETWORK_EVENT_NUD_FAILURE_ROAM = 0; + const int NETWORK_EVENT_NUD_FAILURE_CONFIRM = 1; + const int NETWORK_EVENT_NUD_FAILURE_ORGANIC = 2; + const int NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED = 3; + + /** + * Store a specific network event to database for a given cluster. + * + * @param cluster The cluster representing a notion of network group (e.g., BSSIDs with the + * same SSID). + * @param timestamp The timestamp {@link System.currentTimeMillis} when a specific network + * event occurred. + * @param expiry The timestamp {@link System.currentTimeMillis} when a specific network + * event stored in the database expires, e.g. it might be one week from now. + * @param eventType One of the NETWORK_EVENT constants above. + * @param listener A listener that will be invoked to inform of the completion of this call. + * @return (through the listener) A status to indicate success or failure. + */ + void storeNetworkEvent(String cluster, long timestamp, long expiry, int eventType, + IOnStatusListener listener); + + /** + * Retrieve the specific network event counts for a given cluster and event type since one or + * more timestamps in the past. + * + * @param cluster The cluster to query. + * @param sinceTimes An array of timestamps in the past. The query will return an array of + * equal size. Each element in the array will contain the number of network + * events between the corresponding timestamp and the current time, e.g. query + * since the last week and/or the last day. + * @param eventTypes An array of network event types to query, which can be one or more of the + * above NETWORK_EVENT constants. + * @param listener The listener that will be invoked to return the answer. + * @return (through the listener) The event counts associated with the query, or an empty array + * if the query failed. + */ + void retrieveNetworkEventCount(String cluster, in long[] sinceTimes, in int[] eventTypes, + IOnNetworkEventCountRetrievedListener listener); }
diff --git a/common/networkstackclient/src/android/net/IpMemoryStoreClient.java b/common/networkstackclient/src/android/net/IpMemoryStoreClient.java index a1c5694..8b93124 100644 --- a/common/networkstackclient/src/android/net/IpMemoryStoreClient.java +++ b/common/networkstackclient/src/android/net/IpMemoryStoreClient.java
@@ -25,6 +25,7 @@ import android.net.ipmemorystore.OnDeleteStatusListener; import android.net.ipmemorystore.OnL2KeyResponseListener; import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.OnNetworkEventCountRetrievedListener; import android.net.ipmemorystore.OnSameL3NetworkResponseListener; import android.net.ipmemorystore.OnStatusListener; import android.net.ipmemorystore.Status; @@ -289,4 +290,64 @@ Log.e(TAG, "Error executing factory reset", m); } } + + /** + * Retrieve the specific network event counts for a given cluster and event type since one or + * more timestamps in the past. + * + * @param cluster The cluster to query. + * @param sinceTimes An array of timestamps in the past. The query will return an array of + * equal size. Each element in the array will contain the number of network + * events between the corresponding timestamp and the current time, e.g. query + * since the last week and/or the last day. + * @param eventTypes An array of network event types to query, which can be one or more of the + * above NETWORK_EVENT constants. + * @param listener The listener that will be invoked to return the answer. + * returns (through the listener) The event counts associated with the query, or an empty array + * if the query failed. + */ + public void retrieveNetworkEventCount(@NonNull final String cluster, + @NonNull final long[] sinceTimes, + @NonNull final int[] eventTypes, + @Nullable final OnNetworkEventCountRetrievedListener listener) { + try { + runWhenServiceReady(service -> ignoringRemoteException( + () -> service.retrieveNetworkEventCount(cluster, sinceTimes, eventTypes, + OnNetworkEventCountRetrievedListener.toAIDL(listener)))); + } catch (ExecutionException m) { + ignoringRemoteException("Error retrieving network event count", + () -> listener.onNetworkEventCountRetrieved( + new Status(Status.ERROR_UNKNOWN), + new int[0]) /* empty counts */); + } + } + + /** + * Store a specific network event to database for a given cluster. + * + * @param cluster The cluster representing a notion of network group (e.g., BSSIDs with the + * same SSID). + * @param timestamp The timestamp {@link System.currentTimeMillis} when a specific network + * event occurred. + * @param expiry The timestamp {@link System.currentTimeMillis} when a specific network + * event stored in the database expires, e.g. it might be one week from now. + * @param eventType One of the NETWORK_EVENT constants above. + * @param listener A listener that will be invoked to inform of the completion of this call. + * returns (through the listener) A status to indicate success or failure. + */ + public void storeNetworkEvent(@NonNull final String cluster, + final long timestamp, + final long expiry, + final int eventType, + @Nullable final OnStatusListener listener) { + try { + runWhenServiceReady(service -> ignoringRemoteException( + () -> service.storeNetworkEvent(cluster, timestamp, expiry, eventType, + OnStatusListener.toAIDL(listener)))); + } catch (ExecutionException m) { + if (null == listener) return; + ignoringRemoteException("Error storing network event", + () -> listener.onComplete(new Status(Status.ERROR_UNKNOWN))); + } + } }
diff --git a/common/networkstackclient/src/android/net/PrivateDnsConfigParcel.aidl b/common/networkstackclient/src/android/net/PrivateDnsConfigParcel.aidl index e747d61..2b4bc3f 100644 --- a/common/networkstackclient/src/android/net/PrivateDnsConfigParcel.aidl +++ b/common/networkstackclient/src/android/net/PrivateDnsConfigParcel.aidl
@@ -72,4 +72,12 @@ * The port used to reach the DoH servers. */ int dohPort = -1; + + /** + * Whether DDR discovery is enabled. If DDR is enabled, DoH servers will only be discovered + * using DDR. If DDR is not enabled, DoH servers will only be discovered using the list of + * known providers hardcoded in DnsResolver. + */ + boolean ddrEnabled = false; + }
diff --git a/common/networkstackclient/src/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl b/common/networkstackclient/src/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl new file mode 100644 index 0000000..b5ef0a1 --- /dev/null +++ b/common/networkstackclient/src/android/net/ipmemorystore/IOnNetworkEventCountRetrievedListener.aidl
@@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipmemorystore; + +import android.net.ipmemorystore.StatusParcelable; + +/** + * A listener for the IpMemoryStore to return the counts of network event that matches the query. + * {@hide} + */ +oneway interface IOnNetworkEventCountRetrievedListener { + /** + * The network event counts were fetched for a specified cluster and network event types + * (IIpMemoryStore#NETWORK_EVENT_* constants) since one or more timestamps in the past. + * + * See {@link IIpMemoryStore#retrieveNetworkEventCount} parameter description for more details. + */ + void onNetworkEventCountRetrieved(in StatusParcelable status, in int[] counts); +}
diff --git a/common/networkstackclient/src/android/net/ipmemorystore/OnNetworkEventCountRetrievedListener.java b/common/networkstackclient/src/android/net/ipmemorystore/OnNetworkEventCountRetrievedListener.java new file mode 100644 index 0000000..1c30150 --- /dev/null +++ b/common/networkstackclient/src/android/net/ipmemorystore/OnNetworkEventCountRetrievedListener.java
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return specific network event counts. + * @hide + */ +public interface OnNetworkEventCountRetrievedListener { + /** + * The memory store has come up with the answer to a query that was sent. + */ + void onNetworkEventCountRetrieved(Status status, int[] counts); + + /** Converts this OnNetworkEventCountRetrievedListener to a parcelable object */ + @NonNull + static IOnNetworkEventCountRetrievedListener toAIDL( + @NonNull final OnNetworkEventCountRetrievedListener listener) { + return new IOnNetworkEventCountRetrievedListener.Stub() { + @Override + public void onNetworkEventCountRetrieved( + final StatusParcelable statusParcelable, + final int[] counts) { + // NonNull, but still don't crash the system server if null + if (null != listener) { + listener.onNetworkEventCountRetrieved(new Status(statusParcelable), counts); + } + } + + @Override + public int getInterfaceVersion() { + return this.VERSION; + } + + @Override + public String getInterfaceHash() { + return this.HASH; + } + }; + } +}
diff --git a/common/networkstackclient/src/android/net/shared/PrivateDnsConfig.java b/common/networkstackclient/src/android/net/shared/PrivateDnsConfig.java index 632d1d6..9752bae 100644 --- a/common/networkstackclient/src/android/net/shared/PrivateDnsConfig.java +++ b/common/networkstackclient/src/android/net/shared/PrivateDnsConfig.java
@@ -41,6 +41,12 @@ @NonNull public final InetAddress[] ips; + // Whether DDR discovery is enabled. + // If DDR is enabled, then empty dohName / dohIps indicate that DoH is disabled. + // If DDR is disabled, then empty dohName / dohIps indicate that DNS resolver should attempt to + // enable DoH based on using its hardcoded list of known providers. + public final boolean ddrEnabled; + // These fields store the DoH information discovered from SVCB lookups. @NonNull public final String dohName; @@ -67,8 +73,8 @@ */ public PrivateDnsConfig(boolean useTls) { this(useTls ? PRIVATE_DNS_MODE_OPPORTUNISTIC : PRIVATE_DNS_MODE_OFF, null /* hostname */, - null /* ips */, null /* dohName */, null /* dohIps */, null /* dohPath */, - -1 /* dohPort */); + null /* ips */, false /* ddrEnabled */, null /* dohName */, null /* dohIps */, + null /* dohPath */, -1 /* dohPort */); } /** @@ -78,8 +84,8 @@ */ public PrivateDnsConfig(@Nullable String hostname, @Nullable InetAddress[] ips) { this(TextUtils.isEmpty(hostname) ? PRIVATE_DNS_MODE_OFF : - PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, hostname, ips, null /* dohName */, - null /* dohIps */, null /* dohPath */, -1 /* dohPort */); + PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, hostname, ips, false /* ddrEnabled */, + null /* dohName */, null /* dohIps */, null /* dohPath */, -1 /* dohPort */); } /** @@ -88,11 +94,12 @@ * and empty arrays as equivalent. */ public PrivateDnsConfig(int mode, @Nullable String hostname, @Nullable InetAddress[] ips, - @Nullable String dohName, @Nullable InetAddress[] dohIps, @Nullable String dohPath, - int dohPort) { + boolean ddrEnabled, @Nullable String dohName, @Nullable InetAddress[] dohIps, + @Nullable String dohPath, int dohPort) { this.mode = mode; this.hostname = (hostname != null) ? hostname : ""; this.ips = (ips != null) ? ips.clone() : new InetAddress[0]; + this.ddrEnabled = ddrEnabled; this.dohName = (dohName != null) ? dohName : ""; this.dohIps = (dohIps != null) ? dohIps.clone() : new InetAddress[0]; this.dohPath = (dohPath != null) ? dohPath : ""; @@ -103,6 +110,7 @@ mode = cfg.mode; hostname = cfg.hostname; ips = cfg.ips; + ddrEnabled = cfg.ddrEnabled; dohName = cfg.dohName; dohIps = cfg.dohIps; dohPath = cfg.dohPath; @@ -123,6 +131,13 @@ return mode == PRIVATE_DNS_MODE_OPPORTUNISTIC; } + /** + * Returns whether the fields related to private DNS settings are the same. + */ + public boolean areSettingsSameAs(PrivateDnsConfig other) { + return mode == other.mode && TextUtils.equals(hostname, other.hostname); + } + @Override public String toString() { return PrivateDnsConfig.class.getSimpleName() @@ -158,6 +173,7 @@ Arrays.asList(dohIps), IpConfigurationParcelableUtil::parcelAddress, String.class); parcel.dohPath = dohPath; parcel.dohPort = dohPort; + parcel.ddrEnabled = ddrEnabled; return parcel; } @@ -187,7 +203,7 @@ InetAddress[] dohIps = new InetAddress[parcel.dohIps.length]; dohIps = fromParcelableArray(parcel.dohIps, IpConfigurationParcelableUtil::unparcelAddress).toArray(dohIps); - return new PrivateDnsConfig(parcel.privateDnsMode, parcel.hostname, ips, parcel.dohName, - dohIps, parcel.dohPath, parcel.dohPort); + return new PrivateDnsConfig(parcel.privateDnsMode, parcel.hostname, ips, + parcel.ddrEnabled, parcel.dohName, dohIps, parcel.dohPath, parcel.dohPort); } }
diff --git a/src/android/net/apf/AndroidPacketFilter.java b/src/android/net/apf/AndroidPacketFilter.java index 6dd4fad..c88587b 100644 --- a/src/android/net/apf/AndroidPacketFilter.java +++ b/src/android/net/apf/AndroidPacketFilter.java
@@ -113,4 +113,11 @@ default boolean supportNdOffload() { return false; } + + /** + * Return if the ApfFilter should enable mDNS offload. + */ + default boolean shouldEnableMdnsOffload() { + return false; + } }
diff --git a/src/android/net/apf/ApfConstants.java b/src/android/net/apf/ApfConstants.java index 09be67b..a23e970 100644 --- a/src/android/net/apf/ApfConstants.java +++ b/src/android/net/apf/ApfConstants.java
@@ -87,6 +87,8 @@ public static final int ICMP6_MTU_OPTION_TYPE = 5; // From RFC6106: Recursive DNS Server option public static final int ICMP6_RDNSS_OPTION_TYPE = 25; + // From RFC5175: RA Flags Extension option + public static final int ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE = 26; // From RFC6106: DNS Search List option public static final int ICMP6_DNSSL_OPTION_TYPE = 31; // From RFC8910: Captive-Portal option
diff --git a/src/android/net/apf/ApfCounterTracker.java b/src/android/net/apf/ApfCounterTracker.java index 6c5b566..9700b5b 100644 --- a/src/android/net/apf/ApfCounterTracker.java +++ b/src/android/net/apf/ApfCounterTracker.java
@@ -59,6 +59,7 @@ PASSED_ARP_UNICAST_REPLY, PASSED_ARP_UNKNOWN, PASSED_DHCP, + PASSED_ETHER_OUR_SRC_MAC, PASSED_IPV4, PASSED_IPV4_FROM_DHCPV4_SERVER, PASSED_IPV4_UNICAST, @@ -203,7 +204,7 @@ value = 0; } long oldValue = mCounters.getOrDefault(counter, 0L); - // All counters are increamental + // All counters are incremental if (value > oldValue) { mCounters.put(counter, value); } @@ -216,4 +217,11 @@ public Map<Counter, Long> getCounters() { return mCounters; } + + /** + * Clear all counters. + */ + public void clearCounters() { + mCounters.clear(); + } }
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java index c3dc9ac..90bd832 100644 --- a/src/android/net/apf/ApfFilter.java +++ b/src/android/net/apf/ApfFilter.java
@@ -52,6 +52,7 @@ import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET; import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_LEN; import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_OFFSET; +import static android.net.apf.ApfConstants.ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE; import static android.net.apf.ApfConstants.ICMP6_RA_OPTION_OFFSET; import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_LEN; import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_OFFSET; @@ -87,6 +88,7 @@ import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST; import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_16384THS; import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_SECONDS; +import static android.net.apf.ApfCounterTracker.Counter.PASSED_ETHER_OUR_SRC_MAC; import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_DAD; import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_SLLA_OPTION; import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_TENTATIVE; @@ -94,6 +96,8 @@ import static android.net.apf.BaseApfGenerator.MemorySlot; import static android.net.apf.BaseApfGenerator.Register.R0; import static android.net.apf.BaseApfGenerator.Register.R1; +import static android.net.nsd.OffloadEngine.OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK; +import static android.net.nsd.OffloadEngine.OFFLOAD_TYPE_REPLY; import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; @@ -106,6 +110,7 @@ import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_CLOEXEC; +import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; @@ -124,8 +129,10 @@ import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; +import android.annotation.ChecksSdkIntAtLeast; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -138,6 +145,11 @@ import android.net.apf.ApfCounterTracker.Counter; import android.net.apf.BaseApfGenerator.IllegalInstructionException; import android.net.ip.IpClient.IpClientCallbacksWrapper; +import android.net.nsd.NsdManager; +import android.net.nsd.OffloadEngine; +import android.net.nsd.OffloadServiceInfo; +import android.os.Build; +import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; import android.stats.connectivity.NetworkQuirkEvent; @@ -158,14 +170,13 @@ import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.ConnectivityUtils; import com.android.net.module.util.InterfaceParams; -import com.android.net.module.util.SocketUtils; +import com.android.net.module.util.PacketReader; import com.android.networkstack.metrics.ApfSessionInfoMetrics; import com.android.networkstack.metrics.IpClientRaInfoMetrics; import com.android.networkstack.metrics.NetworkQuirkMetrics; import com.android.networkstack.util.NetworkStackUtils; import java.io.FileDescriptor; -import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -186,16 +197,8 @@ * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to * filter out redundant duplicate ones. * <p> - * Threading model: - * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to - * know what RAs to filter for, thus generating APF programs is dependent on mRas. - * mRas can be accessed by multiple threads: - * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. - * - callers of: - * - setMulticastFilter(), which can cause an APF program to be generated. - * - dump(), which dumps mRas among other things. - * - shutdown(), which clears mRas. - * So access to mRas is synchronized. + * Threading model: this class is not thread-safe and can only be accessed from IpClient's + * handler thread. * * @hide */ @@ -215,39 +218,27 @@ public boolean hasClatInterface; public boolean shouldHandleArpOffload; public boolean shouldHandleNdOffload; + public boolean shouldHandleMdnsOffload; } - // Thread to listen for RAs. - @VisibleForTesting - public class ReceiveThread extends Thread { - private final byte[] mPacket = new byte[1514]; - private final FileDescriptor mSocket; - private volatile boolean mStopped; + private class RaPacketReader extends PacketReader { + private static final int RECEIVE_BUFFER_SIZE = 1514; + private final int mIfIndex; - public ReceiveThread(FileDescriptor socket) { - mSocket = socket; - } - - public void halt() { - mStopped = true; - // Interrupts the read() call the thread is blocked in. - SocketUtils.closeSocketQuietly(mSocket); + RaPacketReader(Handler handler, int ifIndex) { + super(handler, RECEIVE_BUFFER_SIZE); + mIfIndex = ifIndex; } @Override - public void run() { - log("begin monitoring"); - while (!mStopped) { - try { - int length = Os.read(mSocket, mPacket, 0, mPacket.length); - processRa(mPacket, length); - } catch (IOException|ErrnoException e) { - if (!mStopped) { - Log.e(TAG, "Read error", e); - } - } - } + protected FileDescriptor createFd() { + return mDependencies.createPacketReaderSocket(mIfIndex); + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + processRa(recvbuf, length); } } @@ -267,8 +258,8 @@ @VisibleForTesting @NonNull public final byte[] mHardwareAddress; - @VisibleForTesting - public ReceiveThread mReceiveThread; + private final RaPacketReader mRaPacketReader; + private final Handler mHandler; @GuardedBy("this") private long mUniqueCounter; @GuardedBy("this") @@ -305,10 +296,15 @@ private final int mAcceptRaMinLft; private final boolean mShouldHandleArpOffload; private final boolean mShouldHandleNdOffload; + private final boolean mShouldHandleMdnsOffload; private final NetworkQuirkMetrics mNetworkQuirkMetrics; private final IpClientRaInfoMetrics mIpClientRaInfoMetrics; private final ApfSessionInfoMetrics mApfSessionInfoMetrics; + private final NsdManager mNsdManager; + @VisibleForTesting + final List<OffloadServiceInfo> mOffloadServiceInfos = new ArrayList<>(); + private OffloadEngine mOffloadEngine; private static boolean isDeviceIdleModeChangedAction(Intent intent) { return ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction()); @@ -339,16 +335,21 @@ private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final PowerManager powerManager = context.getSystemService(PowerManager.class); - if (isDeviceIdleModeChangedAction(intent) - || isDeviceLightIdleModeChangedAction(intent)) { - final boolean deviceIdle = powerManager.isDeviceIdleMode() - || isDeviceLightIdleMode(powerManager); - setDozeMode(deviceIdle); - } + mHandler.post(() -> { + if (mIsApfShutdown) return; + final PowerManager powerManager = context.getSystemService(PowerManager.class); + if (isDeviceIdleModeChangedAction(intent) + || isDeviceLightIdleModeChangedAction(intent)) { + final boolean deviceIdle = powerManager.isDeviceIdleMode() + || isDeviceLightIdleMode(powerManager); + setDozeMode(deviceIdle); + } + }); } }; + private boolean mIsApfShutdown; + // Our IPv4 address, if we have just one, otherwise null. @GuardedBy("this") private byte[] mIPv4Address; @@ -375,16 +376,64 @@ private final Dependencies mDependencies; - public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, - IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics) { - this(context, config, ifParams, ipClientCallback, networkQuirkMetrics, + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + private void registerOffloadEngine() { + if (mOffloadEngine != null) { + Log.wtf(TAG, + "registerOffloadEngine called twice without calling unregisterOffloadEngine"); + return; + } + mOffloadEngine = new OffloadEngine() { + @Override + public void onOffloadServiceUpdated(@NonNull OffloadServiceInfo info) { + mOffloadServiceInfos.removeIf(i -> i.getKey().equals(info.getKey())); + mOffloadServiceInfos.add(info); + } + + @Override + public void onOffloadServiceRemoved(@NonNull OffloadServiceInfo info) { + mOffloadServiceInfos.removeIf(i -> i.getKey().equals(info.getKey())); + } + }; + mNsdManager.registerOffloadEngine(mInterfaceParams.name, + OFFLOAD_TYPE_REPLY, + OFFLOAD_CAPABILITY_BYPASS_MULTICAST_LOCK, + mHandler::post, mOffloadEngine); + } + + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + private void unregisterOffloadEngine() { + if (mOffloadEngine != null) { + mNsdManager.unregisterOffloadEngine(mOffloadEngine); + mOffloadServiceInfos.clear(); + mOffloadEngine = null; + } + } + + public ApfFilter(Handler handler, Context context, ApfConfiguration config, + InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, + NetworkQuirkMetrics networkQuirkMetrics) { + this(handler, context, config, ifParams, ipClientCallback, networkQuirkMetrics, new Dependencies(context)); } + private synchronized void maybeCleanUpApfRam() { + // Clear the APF memory to reset all counters upon connecting to the first AP + // in an SSID. This is limited to APFv3 devices because this large write triggers + // a crash on some older devices (b/78905546). + if (hasDataAccess(mApfVersionSupported)) { + byte[] zeroes = new byte[mApfRamSize]; + if (!mIpClientCallback.installPacketFilter(zeroes)) { + sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); + } + } + } + @VisibleForTesting - public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, - IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, - Dependencies dependencies) { + public ApfFilter(Handler handler, Context context, ApfConfiguration config, + InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, + NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies) { + mHandler = handler; mApfVersionSupported = config.apfVersionSupported; mApfRamSize = config.apfRamSize; mInstallableProgramSizeClamp = config.installableProgramSizeClamp; @@ -406,6 +455,7 @@ mAcceptRaMinLft = config.acceptRaMinLft; mShouldHandleArpOffload = config.shouldHandleArpOffload; mShouldHandleNdOffload = config.shouldHandleNdOffload; + mShouldHandleMdnsOffload = config.shouldHandleMdnsOffload; mDependencies = dependencies; mNetworkQuirkMetrics = networkQuirkMetrics; mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics(); @@ -414,6 +464,8 @@ mMinMetricsSessionDurationMs = config.minMetricsSessionDurationMs; mHasClat = config.hasClatInterface; + mIsApfShutdown = false; + // Now fill the black list from the passed array mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList); @@ -429,31 +481,23 @@ mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); // TODO: ApfFilter should not generate programs until IpClient sends provisioning success. synchronized (this) { - // Clear the APF memory to reset all counters upon connecting to the first AP - // in an SSID. This is limited to APFv3 devices because this large write triggers - // a crash on some older devices (b/78905546). - if (hasDataAccess(mApfVersionSupported)) { - byte[] zeroes = new byte[mApfRamSize]; - if (!mIpClientCallback.installPacketFilter(zeroes)) { - sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); - } - } - + maybeCleanUpApfRam(); // Install basic filters installNewProgramLocked(); } - FileDescriptor socket = mDependencies.createRaReaderSocket(mInterfaceParams.index); - if (socket != null) { - mReceiveThread = new ReceiveThread(socket); - mReceiveThread.start(); + + mRaPacketReader = new RaPacketReader(mHandler, mInterfaceParams.index); + // The class constructor must be called from the IpClient's handler thread + if (!mRaPacketReader.start()) { + Log.wtf(TAG, "Failed to start RaPacketReader"); } // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter. mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver); - mDependencies.onApfFilterCreated(this); - if (mReceiveThread != null) { - mDependencies.onThreadCreated(mReceiveThread); + mNsdManager = context.getSystemService(NsdManager.class); + if (shouldEnableMdnsOffload()) { + registerOffloadEngine(); } } @@ -471,10 +515,10 @@ * Create a socket to read RAs. */ @Nullable - public FileDescriptor createRaReaderSocket(int ifIndex) { + public FileDescriptor createPacketReaderSocket(int ifIndex) { FileDescriptor socket; try { - socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0); + socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); NetworkStackUtils.attachRaFilter(socket); SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, ifIndex); Os.bind(socket, addr); @@ -1011,6 +1055,7 @@ case ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE: case ICMP6_MTU_OPTION_TYPE: case ICMP6_PREF64_OPTION_TYPE: + case ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE: addMatchSection(optionLength); break; case ICMP6_CAPTIVE_PORTAL_OPTION_TYPE: // unlikely to ever change. @@ -1679,7 +1724,14 @@ // Check 1) it's not a fragment. 2) it's UDP. // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET); - gen.addAnd(0x3FFF00FF); + // Mask out the reserved and don't fragment bits, plus the TTL field. + // Because: + // IPV4_FRAGMENT_OFFSET_MASK = 0x1fff + // IPV4_FRAGMENT_MORE_FRAGS_MASK = 0x2000 + // hence this constant ends up being 0x3FFF00FF. + // We want the more flag bit and offset to be 0 (ie. not a fragment), + // so after this masking we end up with just the ip protocol (hopefully UDP). + gen.addAnd((IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK) << 16 | 0xFF); gen.addCountAndDropIfR0NotEquals(IPPROTO_UDP, Counter.DROPPED_IPV4_NON_DHCP4); // Check it's addressed to DHCP client port. gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); @@ -1697,7 +1749,8 @@ // Check 1) it's not a fragment. 2) it's UDP. // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET); - gen.addAnd(0x3FFF00FF); + // see above for explanation of this constant + gen.addAnd((IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK) << 16 | 0xFF); gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); // Check it's addressed to DHCP client port. gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); @@ -1993,7 +2046,7 @@ // if there is a hop-by-hop option present (e.g. MLD query) // pass // if we're dropping multicast - // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode: + // if it's not ICMPv6 or it's ICMPv6 but we're in doze mode: // if it's multicast: // drop // pass @@ -2275,6 +2328,8 @@ // Here's a basic summary of what the initial program does: // + // if it is a loopback (src mac is nic's primary mac) packet + // pass // if it's a 802.3 Frame (ethtype < 0x0600): // drop or pass based on configurations // if it has a ether-type that belongs to the black list @@ -2289,6 +2344,9 @@ // pass // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets + gen.addLoadImmediate(R0, ETHER_SRC_ADDR_OFFSET); + gen.addCountAndPassIfBytesAtR0Equal(mHardwareAddress, PASSED_ETHER_OUR_SRC_MAC); + gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET); if (SdkLevel.isAtLeastV()) { // IPv4, ARP, IPv6, EAPOL, WAPI @@ -2371,9 +2429,10 @@ final byte[] program; int programMinLft = Integer.MAX_VALUE; - // Ensure the entire APF program uses the same time base. - int timeSeconds = secondsSinceBoot(); try { + // Ensure the entire APF program uses the same time base. + final int timeSeconds = secondsSinceBoot(); + mLastTimeInstalledProgram = timeSeconds; // Step 1: Determine how many RA filters we can fit in the program. ApfV4GeneratorBase<?> gen = emitPrologueLocked(); @@ -2422,7 +2481,6 @@ sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); } } - mLastTimeInstalledProgram = timeSeconds; mLastInstalledProgramMinLifetime = programMinLft; mLastInstalledProgram = program; mNumProgramUpdates++; @@ -2532,7 +2590,7 @@ * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet * filtering using APF programs. */ - public static ApfFilter maybeCreate(Context context, ApfConfiguration config, + public static ApfFilter maybeCreate(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics) { if (context == null || config == null || ifParams == null) return null; @@ -2544,7 +2602,8 @@ return null; } - return new ApfFilter(context, config, ifParams, ipClientCallback, networkQuirkMetrics); + return new ApfFilter(handler, context, config, ifParams, ipClientCallback, + networkQuirkMetrics); } private synchronized void collectAndSendMetrics() { @@ -2579,13 +2638,14 @@ public synchronized void shutdown() { collectAndSendMetrics(); - if (mReceiveThread != null) { - log("shutting down"); - mReceiveThread.halt(); // Also closes socket. - mReceiveThread = null; - } + // The shutdown() must be called from the IpClient's handler thread + mRaPacketReader.stop(); mRas.clear(); mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver); + mIsApfShutdown = true; + if (shouldEnableMdnsOffload()) { + unregisterOffloadEngine(); + } } public synchronized void setMulticastFilter(boolean isEnabled) { @@ -2683,6 +2743,13 @@ return shouldUseApfV6Generator() && mShouldHandleNdOffload; } + @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */, codename = + "VanillaIceCream") + @Override + public boolean shouldEnableMdnsOffload() { + return shouldUseApfV6Generator() && mShouldHandleMdnsOffload; + } + private boolean shouldUseApfV6Generator() { return SdkLevel.isAtLeastV() && ApfV6Generator.supportsVersion(mApfVersionSupported); } @@ -2742,12 +2809,12 @@ } public synchronized void dump(IndentingPrintWriter pw) { + // TODO: use HandlerUtils.runWithScissors() to dump APF on the handler thread. pw.println(String.format( "Capabilities: { apfVersionSupported: %d, maximumApfProgramSize: %d }", mApfVersionSupported, mApfRamSize)); pw.println("InstallableProgramSizeClamp: " + mInstallableProgramSizeClamp); pw.println("Filter update status: " + (mIsRunning ? "RUNNING" : "PAUSED")); - pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec); pw.println("Interface MAC address: " + MacAddress.fromBytes(mHardwareAddress)); @@ -2906,6 +2973,11 @@ /** Resume ApfFilter updates for testing purposes. */ public void resume() { + maybeCleanUpApfRam(); + // Since the resume() function and cleanup process invalidate previous counter + // snapshots, the ApfCounterTracker needs to be reset to maintain reliable, incremental + // counter tracking. + mApfCounterTracker.clearCounters(); mIsRunning = true; }
diff --git a/src/android/net/ip/ConnectivityPacketTracker.java b/src/android/net/ip/ConnectivityPacketTracker.java index 51fb428..c071a1b 100644 --- a/src/android/net/ip/ConnectivityPacketTracker.java +++ b/src/android/net/ip/ConnectivityPacketTracker.java
@@ -16,12 +16,15 @@ package android.net.ip; +import static android.net.util.SocketUtils.closeSocket; import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.system.OsConstants.AF_PACKET; import static android.system.OsConstants.ETH_P_ALL; import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + import android.net.util.ConnectivityPacketSummary; import android.os.Handler; import android.os.SystemClock; @@ -30,7 +33,12 @@ import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; +import android.util.LruCache; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.TokenBucket; import com.android.net.module.util.InterfaceParams; @@ -39,6 +47,8 @@ import java.io.FileDescriptor; import java.io.IOException; +import java.util.Arrays; +import java.util.Objects; /** @@ -58,6 +68,50 @@ * @hide */ public class ConnectivityPacketTracker { + /** + * Dependencies class for testing. + */ + @VisibleForTesting(visibility = PRIVATE) + public static class Dependencies { + private final LocalLog mLog; + public Dependencies(final LocalLog log) { + mLog = log; + } + + /** + * Create a socket to read RAs. + */ + @Nullable + public FileDescriptor createPacketReaderSocket(int ifIndex) { + FileDescriptor socket = null; + try { + socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); + NetworkStackUtils.attachControlPacketFilter(socket); + Os.bind(socket, makePacketSocketAddress(ETH_P_ALL, ifIndex)); + } catch (ErrnoException | IOException e) { + final String msg = "Failed to create packet tracking socket: "; + Log.e(TAG, msg, e); + mLog.log(msg + e); + closeFd(socket); + return null; + } + return socket; + } + + public int getMaxCapturePktSize() { + return MAX_CAPTURE_PACKET_SIZE; + } + + private void closeFd(FileDescriptor fd) { + try { + closeSocket(fd); + } catch (IOException e) { + Log.e(TAG, "failed to close socket"); + } + } + } + + public static final int MAX_CAPTURE_TIME_MS = 300000; private static final String TAG = ConnectivityPacketTracker.class.getSimpleName(); private static final boolean DBG = false; private static final String MARK_START = "--- START ---"; @@ -67,21 +121,56 @@ // Use a TokenBucket to limit CPU usage of logging packets in steady state. private static final int TOKEN_FILL_RATE = 50; // Maximum one packet every 20ms. private static final int MAX_BURST_LENGTH = 100; // Maximum burst 100 packets. + private static final int MAX_CAPTURE_PACKET_SIZE = 100; // Maximum capture packet size private final String mTag; private final LocalLog mLog; private final PacketReader mPacketListener; private final TokenBucket mTokenBucket = new TokenBucket(TOKEN_FILL_RATE, MAX_BURST_LENGTH); + // store packet hex string in uppercase as key, receive packet count as value + private final LruCache<String, Integer> mPacketCache; + private final Dependencies mDependencies; private long mLastRateLimitLogTimeMs = 0; private boolean mRunning; + private boolean mCapturing; private String mDisplayName; public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) { - if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams"); + this(h, ifParams, log, new Dependencies(log)); + } - mTag = TAG + "." + ifParams.name; - mLog = log; - mPacketListener = new PacketListener(h, ifParams); + /** + * Sets the capture state. + * + * <p>This method controls whether packet capture is enabled. If capture is disabled, + * the internal packet map is cleared.</p> + * + * @param isCapture {@code true} to enable capture, {@code false} to disable capture + */ + public void setCapture(boolean isCapture) { + // prevent configure the duplicated events + if (mCapturing == isCapture) { + return; + } + + mCapturing = isCapture; + if (!isCapture) { + mPacketCache.evictAll(); + } + } + + /** + * Gets the count of matched packets for a given pattern. + * + * <p>This method searches the internal packet map for packets matching the specified pattern + * and returns the count of such packets.</p> + * + * @param packet The hex string pattern to match against + * @return The count of packets matching the pattern, or 0 if no matches are found + */ + public int getMatchedPacketCount(String packet) { + final Integer count = mPacketCache.get(packet); + return (count != null) ? count : 0; } public void start(String displayName) { @@ -96,6 +185,28 @@ mDisplayName = null; } + public boolean isCapturing() { + return mCapturing; + } + + @VisibleForTesting(visibility = PRIVATE) + public int getTotalCapturePacketCount() { + return mPacketCache.size(); + } + + @VisibleForTesting(visibility = PRIVATE) + public ConnectivityPacketTracker( + @NonNull Handler handler, + @NonNull InterfaceParams ifParams, + @NonNull LocalLog log, + @NonNull Dependencies dependencies) { + mTag = TAG + "." + Objects.requireNonNull(ifParams).name; + mLog = log; + mPacketListener = new PacketListener(handler, ifParams); + mDependencies = dependencies; + mPacketCache = new LruCache<>(mDependencies.getMaxCapturePktSize()); + } + private final class PacketListener extends PacketReader { private final InterfaceParams mInterface; @@ -106,21 +217,13 @@ @Override protected FileDescriptor createFd() { - FileDescriptor s = null; - try { - s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); - NetworkStackUtils.attachControlPacketFilter(s); - Os.bind(s, makePacketSocketAddress(ETH_P_ALL, mInterface.index)); - } catch (ErrnoException | IOException e) { - logError("Failed to create packet tracking socket: ", e); - closeFd(s); - return null; - } - return s; + return mDependencies.createPacketReaderSocket(mInterface.index); } @Override protected void handlePacket(byte[] recvbuf, int length) { + capturePacket(recvbuf, length); + if (!mTokenBucket.get()) { // Rate limited. Log once every second so the user knows packets are missing. final long now = SystemClock.elapsedRealtime(); @@ -171,5 +274,21 @@ private void addLogEntry(String entry) { mLog.log(entry); } + + private void capturePacket(byte[] recvbuf, int length) { + if (!mCapturing) { + return; + } + + byte[] pkt = Arrays.copyOfRange( + recvbuf, 0, Math.min(recvbuf.length, length)); + final String pktHexString = HexDump.toHexString(pkt); + final Integer pktCnt = mPacketCache.get(pktHexString); + if (pktCnt == null) { + mPacketCache.put(pktHexString, 1); + } else { + mPacketCache.put(pktHexString, pktCnt + 1); + } + } } }
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 9bc13bd..8d60804 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java
@@ -26,6 +26,7 @@ import static android.net.ip.IIpClientCallbacks.DTIM_MULTIPLIER_RESET; import static android.net.ip.IpClient.IpClientCommands.CMD_ADDRESSES_CLEARED; import static android.net.ip.IpClient.IpClientCommands.CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF; +import static android.net.ip.IpClient.IpClientCommands.CMD_APF_STOP_CAPTURE; import static android.net.ip.IpClient.IpClientCommands.CMD_COMPLETE_PRECONNECTION; import static android.net.ip.IpClient.IpClientCommands.CMD_CONFIRM; import static android.net.ip.IpClient.IpClientCommands.CMD_JUMP_RUNNING_TO_STOPPING; @@ -55,6 +56,7 @@ import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.stats.connectivity.NetworkQuirkEvent.QE_DHCP6_HEURISTIC_TRIGGERED; +import static android.stats.connectivity.NetworkQuirkEvent.QE_DHCP6_PD_PROVISIONED; import static android.system.OsConstants.AF_PACKET; import static android.system.OsConstants.ARPHRD_ETHER; import static android.system.OsConstants.ETH_P_ARP; @@ -159,6 +161,7 @@ import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.ConnectivityUtils; import com.android.net.module.util.DeviceConfigUtils; +import com.android.net.module.util.HandlerUtils; import com.android.net.module.util.InterfaceParams; import com.android.net.module.util.LinkPropertiesUtils; import com.android.net.module.util.SharedLog; @@ -595,6 +598,8 @@ static final int CMD_UPDATE_APF_CAPABILITIES = 19; static final int EVENT_IPV6_AUTOCONF_TIMEOUT = 20; static final int CMD_UPDATE_APF_DATA_SNAPSHOT = 21; + // Triggered by ApfShellCommand + static final int CMD_APF_STOP_CAPTURE = 22; // Internal commands to use instead of trying to call transitionTo() inside // a given State's enter() method. Calling transitionTo() from enter/exit // encounters a Log.wtf() that can cause trouble on eng builds. @@ -770,6 +775,7 @@ private final boolean mPopulateLinkAddressLifetime; private final boolean mApfShouldHandleArpOffload; private final boolean mApfShouldHandleNdOffload; + private final boolean mApfShouldHandleMdnsOffload; private InterfaceParams mInterfaceParams; @@ -785,6 +791,7 @@ private String mTcpBufferSizes; private ProxyInfo mHttpProxy; private AndroidPacketFilter mApfFilter; + private ConnectivityPacketTracker mPacketTracker; private String mL2Key; // The L2 key for this network, for writing into the memory store private String mCluster; // The cluster for this network, for writing into the memory store private int mCreatorUid; // Uid of app creating the wifi configuration @@ -922,12 +929,13 @@ * APF programs. * @see ApfFilter#maybeCreate */ - public AndroidPacketFilter maybeCreateApfFilter(Context context, + public AndroidPacketFilter maybeCreateApfFilter(Handler handler, Context context, ApfFilter.ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper cb, NetworkQuirkMetrics networkQuirkMetrics, boolean useNewApfFilter) { if (useNewApfFilter) { - return ApfFilter.maybeCreate(context, config, ifParams, cb, networkQuirkMetrics); + return ApfFilter.maybeCreate(handler, context, config, ifParams, cb, + networkQuirkMetrics); } else { return LegacyApfFilter.maybeCreate(context, config, ifParams, cb, networkQuirkMetrics); @@ -1020,6 +1028,8 @@ mContext, APF_HANDLE_ARP_OFFLOAD); mApfShouldHandleNdOffload = mDependencies.isFeatureNotChickenedOut( mContext, APF_HANDLE_ND_OFFLOAD); + // TODO: turn on APF mDNS offload. + mApfShouldHandleMdnsOffload = false; mPopulateLinkAddressLifetime = mDependencies.isFeatureEnabled(context, IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION); @@ -1438,7 +1448,16 @@ pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT"); } } - apfFilter.dump(pw); + final Handler handler = getHandler(); + if (handler == null) { + // This situation is unexpected. The getHandler() function should not return null + // unless the IpClient has stopped running. When the IpClient exits the RunningState + // , it should have already set apfFilter to null. + pw.println("ApfFilter is not null even if IpClient is not running."); + } else { + HandlerUtils.runWithScissorsForDump(handler, () -> apfFilter.dump(pw), + 10_000 /* ms */); + } pw.println("APF log:"); pw.println("mApfDebug: " + mApfDebug); mApfLog.dump(fd, pw, args); @@ -1512,8 +1531,8 @@ } final CompletableFuture<String> result = new CompletableFuture<>(); - - getHandler().post(() -> { + final Handler handler = getHandler(); + handler.post(() -> { try { if (mApfFilter == null) { // IpClient has either stopped or the interface does not support APF. @@ -1551,6 +1570,42 @@ Objects.requireNonNull(snapshot, "No data snapshot recorded."); result.complete(snapshot); break; + case "start-capture": + if (mPacketTracker.isCapturing()) { + result.complete("PacketTracker is already capturing"); + } else { + // remove scheduled stop event if it already in the queue + if (handler.hasMessages(IpClientCommands.CMD_APF_STOP_CAPTURE)) { + handler.removeMessages(IpClientCommands.CMD_APF_STOP_CAPTURE); + } + + mPacketTracker.setCapture(true); + // capture up to 300 sec and stop capturing + sendMessageDelayed( + IpClientCommands.CMD_APF_STOP_CAPTURE, + ConnectivityPacketTracker.MAX_CAPTURE_TIME_MS + ); + result.complete("success"); + } + break; + case "matched-packet-counts": + Objects.requireNonNull(optarg, "No packet pattern provided"); + int pktCnt = mPacketTracker.getMatchedPacketCount(optarg); + result.complete(String.valueOf(pktCnt)); + break; + case "stop-capture": + if (!mPacketTracker.isCapturing()) { + result.complete("PacketTracker already stop capturing"); + } else { + // remove scheduled stop event if it already in the queue + if (handler.hasMessages(IpClientCommands.CMD_APF_STOP_CAPTURE)) { + handler.removeMessages(IpClientCommands.CMD_APF_STOP_CAPTURE); + } + + sendMessage(IpClientCommands.CMD_APF_STOP_CAPTURE); + result.complete("success"); + } + break; default: throw new IllegalArgumentException("Invalid apf command: " + cmd); } @@ -2250,6 +2305,13 @@ // the gratuitous NA to update the first-hop router's neighbor cache entry. maybeSendMulticastNSes(newLp); + final boolean gainedV6 = !mLinkProperties.isIpv6Provisioned() && newLp.isIpv6Provisioned(); + // mDelegatedPrefixes is updated as part of the call to assembleLinkProperties() above. + if (gainedV6 && !mDelegatedPrefixes.isEmpty()) { + mNetworkQuirkMetrics.setEvent(QE_DHCP6_PD_PROVISIONED); + mNetworkQuirkMetrics.statsWrite(); + } + // Either success IPv4 or IPv6 provisioning triggers new LinkProperties update, // wait for the provisioning completion and record the latency. mIpProvisioningMetrics.setIPv4ProvisionedLatencyOnFirstTime(newLp.isIpv4Provisioned()); @@ -2645,10 +2707,11 @@ } apfConfig.shouldHandleArpOffload = mApfShouldHandleArpOffload; apfConfig.shouldHandleNdOffload = mApfShouldHandleNdOffload; + apfConfig.shouldHandleMdnsOffload = mApfShouldHandleMdnsOffload; apfConfig.minMetricsSessionDurationMs = mApfCounterPollingIntervalMs; apfConfig.hasClatInterface = mHasSeenClatInterface; - return mDependencies.maybeCreateApfFilter(mContext, apfConfig, mInterfaceParams, - mCallback, mNetworkQuirkMetrics, mUseNewApfFilter); + return mDependencies.maybeCreateApfFilter(getHandler(), mContext, apfConfig, + mInterfaceParams, mCallback, mNetworkQuirkMetrics, mUseNewApfFilter); } private boolean handleUpdateApfCapabilities(@NonNull final ApfCapabilities apfCapabilities) { @@ -3129,7 +3192,6 @@ } class RunningState extends State { - private ConnectivityPacketTracker mPacketTracker; private boolean mDhcpActionInFlight; @Override @@ -3614,7 +3676,9 @@ mCallback.startReadPacketFilter("polling"); sendMessageDelayed(CMD_UPDATE_APF_DATA_SNAPSHOT, mApfCounterPollingIntervalMs); break; - + case CMD_APF_STOP_CAPTURE: + mPacketTracker.setCapture(false); + break; default: return NOT_HANDLED; }
diff --git a/src/android/net/ip/IpReachabilityMonitor.java b/src/android/net/ip/IpReachabilityMonitor.java index 4e8185e..462de90 100644 --- a/src/android/net/ip/IpReachabilityMonitor.java +++ b/src/android/net/ip/IpReachabilityMonitor.java
@@ -30,6 +30,7 @@ import android.content.Context; import android.net.ConnectivityManager; +import android.net.IIpMemoryStore; import android.net.INetd; import android.net.LinkProperties; import android.net.RouteInfo; @@ -837,4 +838,25 @@ return INVALID_REACHABILITY_LOSS_TYPE; } } + + /** + * Convert the NUD critical failure event type to NETWORK_EVENT constant defined in + * IIpMemoryStore. + */ + public static int nudEventTypeToNetworkEvent(final NudEventType type) { + switch (type) { + case NUD_POST_ROAMING_FAILED_CRITICAL: + return IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ROAM; + case NUD_CONFIRM_FAILED_CRITICAL: + return IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_CONFIRM; + case NUD_ORGANIC_FAILED_CRITICAL: + return IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_ORGANIC; + case NUD_POST_ROAMING_MAC_ADDRESS_CHANGED: + case NUD_CONFIRM_MAC_ADDRESS_CHANGED: + case NUD_ORGANIC_MAC_ADDRESS_CHANGED: + return IIpMemoryStore.NETWORK_EVENT_NUD_FAILURE_MAC_ADDRESS_CHANGED; + default: + return INVALID_REACHABILITY_LOSS_TYPE; + } + } }
diff --git a/src/com/android/networkstack/ipmemorystore/IpMemoryStoreDatabase.java b/src/com/android/networkstack/ipmemorystore/IpMemoryStoreDatabase.java index 9e7df82..00026a0 100644 --- a/src/com/android/networkstack/ipmemorystore/IpMemoryStoreDatabase.java +++ b/src/com/android/networkstack/ipmemorystore/IpMemoryStoreDatabase.java
@@ -35,6 +35,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.VisibleForTesting; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.net.InetAddress; @@ -153,7 +155,8 @@ // Update this whenever changing the schema. // DO NOT CHANGE without solid testing for downgrades, and checking onDowngrade // below: b/171340630 - private static final int SCHEMA_VERSION = 4; + @VisibleForTesting + static final int SCHEMA_VERSION = 4; private static final String DATABASE_FILENAME = "IpMemoryStore.db"; private static final String TRIGGER_NAME = "delete_cascade_to_private"; @@ -162,6 +165,12 @@ setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); } + @VisibleForTesting + DbHelper(@NonNull final Context context, int schemaVersion) { + super(context, DATABASE_FILENAME, null, schemaVersion); + setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); + } + /** Called when the database is created */ @Override public void onCreate(@NonNull final SQLiteDatabase db) { @@ -208,11 +217,6 @@ // Downgrades always nuke all data and recreate an empty table. db.execSQL(NetworkAttributesContract.DROP_TABLE); db.execSQL(PrivateDataContract.DROP_TABLE); - // TODO: add test for downgrades. Triggers should already be dropped - // when the table is dropped, so this may be a bug. - // Note that fixing this code does not affect how older versions - // will handle downgrades. - db.execSQL("DROP TRIGGER " + TRIGGER_NAME); onCreate(db); } @@ -749,6 +753,19 @@ } } + static int storeNetworkEvent(@NonNull final SQLiteDatabase db, @NonNull final String cluster, + final long timestamp, final long expiry, final int eventType) { + // TODO: implement this. + return Status.SUCCESS; + } + + static int[] retrieveNetworkEventCount(@NonNull final SQLiteDatabase db, + @NonNull final String cluster, @NonNull final long[] sinceTimes, + @NonNull final int[] eventTypes) { + // TODO: implement this. + return new int[0]; + } + // Helper methods private static String getString(final Cursor cursor, final String columnName) { final int columnIndex = cursor.getColumnIndex(columnName);
diff --git a/src/com/android/networkstack/ipmemorystore/IpMemoryStoreService.java b/src/com/android/networkstack/ipmemorystore/IpMemoryStoreService.java index 76ed56c..a05c5cb 100644 --- a/src/com/android/networkstack/ipmemorystore/IpMemoryStoreService.java +++ b/src/com/android/networkstack/ipmemorystore/IpMemoryStoreService.java
@@ -32,6 +32,7 @@ import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.IOnNetworkEventCountRetrievedListener; import android.net.ipmemorystore.IOnSameL3NetworkResponseListener; import android.net.ipmemorystore.IOnStatusAndCountListener; import android.net.ipmemorystore.IOnStatusListener; @@ -484,6 +485,95 @@ }); } + /** + * Retrieve the specific network event counts for a given cluster and event type since one or + * more timestamps in the past. + * + * @param cluster The cluster to query. + * @param sinceTimes An array of timestamps in the past. The query will return an array of + * equal size. Each element in the array will contain the number of network + * events between the corresponding timestamp and the current time, e.g. query + * since the last week and/or the last day. + * @param eventTypes An array of network event types to query, which can be one or more of the + * above NETWORK_EVENT constants. + * @param listener The listener that will be invoked to return the answer. + * returns (through the listener) The event counts associated with the query, or an empty array + * if the query failed. + */ + @Override + public void retrieveNetworkEventCount(@NonNull final String cluster, + @NonNull final long[] sinceTimes, + @NonNull final int[] eventTypes, + @Nullable final IOnNetworkEventCountRetrievedListener listener) { + if (null == listener) return; + mExecutor.execute(() -> { + try { + if (null == cluster) { + listener.onNetworkEventCountRetrieved( + makeStatus(ERROR_ILLEGAL_ARGUMENT), new int[0] /* counts */); + return; + } + if (null == mDb) { + listener.onNetworkEventCountRetrieved( + makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), new int[0] /* counts */); + return; + } + try { + final int[] counts = IpMemoryStoreDatabase.retrieveNetworkEventCount(mDb, + cluster, sinceTimes, eventTypes); + listener.onNetworkEventCountRetrieved(makeStatus(SUCCESS), counts); + } catch (final Exception e) { + listener.onNetworkEventCountRetrieved(makeStatus(ERROR_GENERIC), + new int[0] /* counts */); + } + } catch (final RemoteException e) { + // Client at the other end died + } + }); + } + + /** + * Store a specific network event to database for a given cluster. + * + * @param cluster The cluster representing a notion of network group (e.g., BSSIDs with the + * same SSID). + * @param timestamp The timestamp {@link System.currentTimeMillis} when a specific network + * event occurred. + * @param expiry The timestamp {@link System.currentTimeMillis} when a specific network + * event stored in the database expires, e.g. it might be one week from now. + * @param eventType One of the NETWORK_EVENT constants above. + * @param listener A listener that will be invoked to inform of the completion of this call. + * returns (through the listener) A status to indicate success or failure. + */ + @Override + public void storeNetworkEvent(@NonNull final String cluster, + final long timestamp, + final long expiry, + final int eventType, + @Nullable final IOnStatusListener listener) { + mExecutor.execute(() -> { + try { + if (null == cluster) { + listener.onComplete(makeStatus(ERROR_ILLEGAL_ARGUMENT)); + return; + } + if (null == mDb) { + listener.onComplete(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED)); + return; + } + try { + final int code = IpMemoryStoreDatabase.storeNetworkEvent(mDb, cluster, + timestamp, expiry, eventType); + if (null != listener) listener.onComplete(makeStatus(code)); + } catch (final Exception e) { + if (null != listener) listener.onComplete(makeStatus(ERROR_GENERIC)); + } + } catch (final RemoteException e) { + // Client at the other end died + } + }); + } + /** Get db size threshold. */ @VisibleForTesting protected int getDbSizeThreshold() {
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java index 33a8308..0c1eb39 100755 --- a/src/com/android/networkstack/util/NetworkStackUtils.java +++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -276,6 +276,7 @@ /** * Experiment flag to enable Discovery of Designated Resolvers (DDR). + * This flag requires networkmonitor_async_privdns_resolution flag. */ public static final String DNS_DDR_VERSION = "dns_ddr_version";
diff --git a/src/com/android/server/NetworkStackService.java b/src/com/android/server/NetworkStackService.java index 4d10c3b..780642f 100644 --- a/src/com/android/server/NetworkStackService.java +++ b/src/com/android/server/NetworkStackService.java
@@ -627,6 +627,14 @@ pw.println(" Format: <apfVersion>,<maxProgramSize>,<packetFormat>"); pw.println(" read"); pw.println(" reads and returns the current state of APF memory."); + pw.println(" start-capture"); + pw.println(" start capture packets in the received buffer."); + pw.println(" The capture is up to 300 sec, then it will stop."); + pw.println(" stop-capture"); + pw.println(" stop capture packets and clear the received buffer."); + pw.println(" matched-packet-counts <pkt-hex-string>"); + pw.println(" the <pkt-hex-string> starts from ether header."); + pw.println(" Expect to do full packet match."); } }
diff --git a/src/com/android/server/connectivity/DdrTracker.java b/src/com/android/server/connectivity/DdrTracker.java index af86914..81d881d 100644 --- a/src/com/android/server/connectivity/DdrTracker.java +++ b/src/com/android/server/connectivity/DdrTracker.java
@@ -16,25 +16,59 @@ package com.android.server.connectivity; +import static android.net.DnsResolver.CLASS_IN; + +import static com.android.net.module.util.CollectionUtils.isEmpty; import static com.android.net.module.util.ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF; import static com.android.net.module.util.ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static com.android.net.module.util.ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static com.android.net.module.util.DnsPacket.TYPE_SVCB; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.DnsResolver; +import android.net.LinkProperties; +import android.net.Network; import android.net.shared.PrivateDnsConfig; +import android.os.CancellationSignal; import android.text.TextUtils; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.DnsPacket; +import com.android.net.module.util.DnsSvcbPacket; +import com.android.net.module.util.SharedLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executor; /** - * A class to perform DDR on a given network (to be implemented). + * A class to perform DDR on a given network. * + * Caller can use startSvcbLookup() to perform DNS SVCB lookup asynchronously. The result of the + * lookup will be passed to callers through the callback onSvcbLookupComplete(). If the result is + * stale, the callback won't be invoked. A result becomes stale once there's a new call to + * startSvcbLookup(). + * + * Threading: + * + * 1. DdrTracker is not thread-safe. All public methods must be executed on the same thread to + * guarantee that all DdrTracker members are synchronized. + * 2. In DdrTracker constructor, an Executor is provided as the execution thread on which the + * callback onSvcbLookupComplete() will be executed. The execution thread must be the same + * as the thread mentioned in 1. */ class DdrTracker { + private static final String TAG = "DDR"; + private static final boolean DBG = true; + @IntDef(prefix = { "PRIVATE_DNS_MODE_" }, value = { PRIVATE_DNS_MODE_OFF, PRIVATE_DNS_MODE_OPPORTUNISTIC, @@ -43,12 +77,71 @@ @Retention(RetentionPolicy.SOURCE) private @interface PrivateDnsMode {} + @VisibleForTesting + static final String DDR_HOSTNAME = "_dns.resolver.arpa"; + + private static final String ALPN_DOH3 = "h3"; + + interface Callback { + /** + * Called on a given execution thread `mExecutor` when a SVCB lookup finishes, unless + * the lookup result is stale. + * The parameter `result` contains the aggregated result that contains both DoH and DoT + * information. + */ + void onSvcbLookupComplete(@NonNull PrivateDnsConfig result); + } + + @NonNull + private final Network mCleartextDnsNetwork; + @NonNull + private final DnsResolver mDnsResolver; + @NonNull + private final Callback mCallback; + + // The execution thread the callback will be executed on. + @NonNull + private final Executor mExecutor; + // Stores the DNS information that is synced with current DNS configuration. @NonNull private DnsInfo mDnsInfo; - DdrTracker() { - mDnsInfo = new DnsInfo(new PrivateDnsConfig(false /* useTls */)); + // Stores the DoT servers discovered from strict mode hostname resolution. + @NonNull + private final List<InetAddress> mDotServers; + + // Stores the result of latest SVCB lookup. + // It is set to null if the result is invalid, for example, lookup timeout or invalid + // SVCB responses. + @Nullable + private DnsSvcbPacket mLatestSvcbPacket = null; + + // Used to check whether a DDR result is stale. + // Given the Threading section documented near the beginning of this file, `mTokenId` ensures + // that mLatestSvcbRecord is always fresh. + @NonNull + private int mTokenId; + + // Used to cancel the in-progress SVCB lookup. + @NonNull + CancellationSignal mCancelSignal; + + private final SharedLog mValidationLogs; + + DdrTracker(@NonNull Network cleartextDnsNetwork, @NonNull DnsResolver dnsResolver, + @NonNull Executor executor, @NonNull Callback callback, SharedLog validationLog) { + mCleartextDnsNetwork = cleartextDnsNetwork; + mDnsResolver = dnsResolver; + mExecutor = executor; + mCallback = callback; + final PrivateDnsConfig privateDnsDisabled = new PrivateDnsConfig(PRIVATE_DNS_MODE_OFF, + null /* hostname */, null /* ips */, true /* ddrEnabled */, null /* dohName */, + null /* dohIps */, null /* dohPath */, -1 /* dohPort */); + mDnsInfo = new DnsInfo(privateDnsDisabled, new ArrayList<>()); + mDotServers = new ArrayList<>(); + mCancelSignal = new CancellationSignal(); + mValidationLogs = validationLog.forSubComponent(TAG); } /** @@ -57,12 +150,44 @@ * returns false. */ boolean notifyPrivateDnsSettingsChanged(@NonNull PrivateDnsConfig cfg) { - if (arePrivateDnsSettingsEquals(cfg, mDnsInfo.cfg)) return false; + if (mDnsInfo.cfg.areSettingsSameAs(cfg)) return false; - mDnsInfo = new DnsInfo(cfg); + ++mTokenId; + mDnsInfo = new DnsInfo(cfg, getDnsServers()); + resetStrictModeHostnameResolutionResult(); return true; } + /** + * If the unencrypted DNS server list on the network has changed (even if only the order has + * changed), this function updates the DnsInfo and returns true; otherwise, the DnsInfo remains + * unchanged and this function returns false. + * + * The reason that this method returns true even if only the order has changed is that + * DnsResolver returns a DNS answer to app side as soon as it receives a DNS response from + * a DNS server. Therefore, the DNS response from the first DNS server that supports DDR + * determines the DDR result. + */ + boolean notifyLinkPropertiesChanged(@NonNull LinkProperties lp) { + final List<InetAddress> servers = lp.getDnsServers(); + + if (servers.equals(getDnsServers())) return false; + + ++mTokenId; + mDnsInfo = new DnsInfo(mDnsInfo.cfg, servers); + return true; + } + + void setStrictModeHostnameResolutionResult(@NonNull InetAddress[] ips) { + resetStrictModeHostnameResolutionResult(); + mDotServers.addAll(Arrays.asList(ips)); + } + + void resetStrictModeHostnameResolutionResult() { + mDotServers.clear(); + } + + @VisibleForTesting @PrivateDnsMode int getPrivateDnsMode() { return mDnsInfo.cfg.mode; } @@ -75,22 +200,263 @@ } @VisibleForTesting - private static boolean arePrivateDnsSettingsEquals(@NonNull PrivateDnsConfig a, - @NonNull PrivateDnsConfig b) { - return a.mode == b.mode && TextUtils.equals(a.hostname, b.hostname); + @NonNull + List<InetAddress> getDnsServers() { + return mDnsInfo.dnsServers; + } + + private boolean hasSvcbAnswer(@NonNull String alpn) { + return (mLatestSvcbPacket != null) ? mLatestSvcbPacket.isSupported(alpn) : false; + } + + @Nullable + private String getTargetNameFromSvcbAnswer(@NonNull String alpn) { + return (mLatestSvcbPacket != null) ? mLatestSvcbPacket.getTargetName(alpn) : null; + } + + // Returns a list of IP addresses for the target name from the latest SVCB packet. + // These may be either from the A/AAAA records in the additional section or from the + // ipv4hint/ipv6hint keys in the SVCB record. + private List<InetAddress> getServersFromSvcbAnswer(@NonNull String alpn) { + return (mLatestSvcbPacket != null) ? mLatestSvcbPacket.getAddresses(alpn) + : Collections.emptyList(); + } + + private int getPortFromSvcbAnswer(@NonNull String alpn) { + return (mLatestSvcbPacket != null) ? mLatestSvcbPacket.getPort(alpn) : -1; + } + + @Nullable + private String getDohPathFromSvcbAnswer(@NonNull String alpn) { + return (mLatestSvcbPacket != null) ? mLatestSvcbPacket.getDohPath(alpn) : null; + } + + @NonNull + private String createHostnameForSvcbQuery() { + final String hostname = getStrictModeHostname(); + if (!TextUtils.isEmpty(hostname)) { + return "_dns." + hostname; + } + return DDR_HOSTNAME; + } + + /** Performs a DNS SVCB Lookup asynchronously. */ + void startSvcbLookup() { + if (getPrivateDnsMode() == PRIVATE_DNS_MODE_OFF) { + // Ensure getResultForReporting returns reasonable results. + mLatestSvcbPacket = null; + // We do not need to increment the token. The token is used to ignore stale results. + // But there can only be lookups in flight if the mode was previously on. Because the + // mode is now off, that means the mode changed, and that incremented the token. + return; + } + // There are some cases where startSvcbLookup() is called twice in a row that + // are likely to lead to the same result, for example: + // 1. A network is connected when private DNS mode is strict mode. + // 2. Private DNS mode is switched to strict mode. + // To avoid duplicate lookups, cancel the in-progress SVCB lookup (if any). + // + // Note that cancelling is not currently very useful because the DNS resolver still + // continues to retry until the query completes or fails. It does prevent the query callback + // from being called, but that's not necessary because the token will not match. + // We still do attempt to cancel the query so future improvements to the DNS resolver could + // use that to do less work. + mCancelSignal.cancel(); + mCancelSignal = new CancellationSignal(); + + // Increment the token ID to stale all in-flight lookups. + // This is for network revalidation in strict mode that a SVCB lookup can be performed + // and its result can be accepted even if there is no DNS configuration change. + final int token = ++mTokenId; + final String hostname = createHostnameForSvcbQuery(); + final DnsResolver.Callback<byte[]> callback = new DnsResolver.Callback<byte[]>() { + boolean isResultFresh() { + return token == mTokenId; + } + + void updateSvcbAnswerAndInvokeUserCallback(@Nullable DnsSvcbPacket result) { + mLatestSvcbPacket = result; + mCallback.onSvcbLookupComplete(getResultForReporting()); + } + + @Override + public void onAnswer(@NonNull byte[] answer, int rcode) { + if (!isResultFresh()) { + validationLog("Ignoring stale SVCB answer"); + return; + } + + if (rcode != 0 || answer.length == 0) { + validationLog("Ignoring invalid SVCB answer: rcode=" + rcode + + " len=" + answer.length); + updateSvcbAnswerAndInvokeUserCallback(null); + return; + } + + final DnsSvcbPacket pkt; + try { + pkt = DnsSvcbPacket.fromResponse(answer); + } catch (DnsPacket.ParseException e) { + validationLog("Ignoring malformed SVCB answer: " + e); + updateSvcbAnswerAndInvokeUserCallback(null); + return; + } + + validationLog("Processing SVCB response: " + pkt); + updateSvcbAnswerAndInvokeUserCallback(pkt); + } + + @Override + public void onError(@NonNull DnsResolver.DnsException e) { + validationLog("DNS error resolving SVCB record for " + hostname + ": " + e); + if (isResultFresh()) { + updateSvcbAnswerAndInvokeUserCallback(null); + } + } + }; + sendDnsSvcbQuery(hostname, mCancelSignal, callback); + } + + /** + * Returns candidate IP addresses to use for DoH. + * + * These can come from A/AAAA records returned by strict mode hostname resolution, from A/AAAA + * records in the additional section of the SVCB response, or from the ipv4hint/ipv6hint keys in + * the H3 ALPN of the SVCB record itself. + * + * RFC 9460 §7.3 says that if A and AAAA records for TargetName are locally available, the + * client SHOULD ignore the hints. + * + * - In opportunistic mode, strict name hostname resolution does not happen, so always use the + * addresses in the SVCB response + * - In strict mode: + * - If the target name in the H3 ALPN matches the strict mode hostname, prefer the result of + * strict mode hostname resolution. + * - If not, prefer the addresses from the SVCB response, but fall back to A/AAAA records if + * there are none. This ensures that: + * - If the strict mode hostname has A/AAAA addresses, those are used even if there are no + * addresses in the SVCB record. + * + * Note that in strict mode, this class always uses the user-specified hostname and ignores the + * target hostname in the SVCB record (see getResultForReporting). In this case, preferring the + * addresses in the SVCB record at ensures that those addresses are used, even if the target + * hostname is not. + */ + private List<InetAddress> getTargetNameIpAddresses(@NonNull String alpn) { + final List<InetAddress> serversFromSvcbAnswer = getServersFromSvcbAnswer(alpn); + final String hostname = getStrictModeHostname(); + if (TextUtils.isEmpty(hostname)) { + return serversFromSvcbAnswer; + } + // Strict mode can use either A/AAAA records coming from strict mode resolution or the + // addresses from the SVCB response (which could be A/AAAA records in the additional section + // or the hints in the SVCB record itself). + final String targetName = getTargetNameFromSvcbAnswer(alpn); + if (TextUtils.equals(targetName, hostname) && !mDotServers.isEmpty()) { + return mDotServers; + } + if (isEmpty(serversFromSvcbAnswer)) { + return mDotServers; + } + return serversFromSvcbAnswer; + } + + /** + * To follow the design of private DNS opportunistic mode, which is similar to RFC 9462 §4.3, + * don't use a designated resolver if its IP address differs from all the unencrypted resolvers' + * IP addresses. + * + * TODO: simplify the code by merging this method with getTargetNameIpAddresses above. + */ + private InetAddress[] getDohServers(@NonNull String alpn) { + final List<InetAddress> candidates = getTargetNameIpAddresses(alpn); + if (isEmpty(candidates)) return null; + if (getPrivateDnsMode() == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) return toArray(candidates); + + candidates.retainAll(getDnsServers()); + return toArray(candidates); + } + + /** + * Returns the aggregated private DNS discovery result as a PrivateDnsConfig. + * getResultForReporting() is called in the following cases: + * 1. when the hostname lookup completes. + * 2. when the SVCB lookup completes. + * + * There is no guarantee which lookup will complete first. Therefore, depending on the private + * DNS mode and the SVCB answer, the return PrivateDnsConfig might be set with DoT, DoH, + * DoT+DoH, or even no servers. + */ + @NonNull + PrivateDnsConfig getResultForReporting() { + final String strictModeHostname = getStrictModeHostname(); + final InetAddress[] dotIps = toArray(mDotServers); + final PrivateDnsConfig candidateResultWithDotOnly = + new PrivateDnsConfig(getPrivateDnsMode(), strictModeHostname, dotIps, + true /* ddrEnabled */, null /* dohName */, null /* dohIps */, + null /* dohPath */, -1 /* dohPort */); + + if (!hasSvcbAnswer(ALPN_DOH3)) { + // TODO(b/240259333): Consider not invoking notifyPrivateDnsConfigResolved() if + // DoT server list is empty. + return candidateResultWithDotOnly; + } + + // The SVCB answer should be fresh. + + final String dohName = (getPrivateDnsMode() == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) + ? strictModeHostname : getTargetNameFromSvcbAnswer(ALPN_DOH3); + final InetAddress[] dohIps = getDohServers(ALPN_DOH3); + final String dohPath = getDohPathFromSvcbAnswer(ALPN_DOH3); + final int dohPort = getPortFromSvcbAnswer(ALPN_DOH3); + + return new PrivateDnsConfig(getPrivateDnsMode(), strictModeHostname, dotIps, true, + dohName, dohIps, dohPath, dohPort); + } + + private void validationLog(String s) { + log(s); + mValidationLogs.log(s); + } + + private void log(String s) { + if (DBG) Log.d(TAG + "/" + mCleartextDnsNetwork.toString(), s); + } + + /** + * A non-blocking call doing DNS SVCB lookup. + */ + private void sendDnsSvcbQuery(String host, @NonNull CancellationSignal cancelSignal, + @NonNull DnsResolver.Callback<byte[]> callback) { + // Note: the even though this code does not pass FLAG_NO_CACHE_LOOKUP, the query is + // currently not cached, because the DNS resolver cache does not cache SVCB records. + // TODO: support caching SVCB records in the DNS resolver cache. + // This should just work but will need testing. + mDnsResolver.rawQuery(mCleartextDnsNetwork, host, CLASS_IN, TYPE_SVCB, 0 /* flags */, + mExecutor, cancelSignal, callback); + } + + private static InetAddress[] toArray(List<InetAddress> list) { + if (list == null) { + return null; + } + return list.toArray(new InetAddress[0]); } /** * A class to store current DNS configuration. Only the information relevant to DDR is stored. * 1. Private DNS setting. - * 2. A list of Unencrypted DNS servers (to be implemented) + * 2. A list of Unencrypted DNS servers. */ private static class DnsInfo { @NonNull public final PrivateDnsConfig cfg; + @NonNull + public final List<InetAddress> dnsServers; - DnsInfo(@NonNull PrivateDnsConfig cfg) { + DnsInfo(@NonNull PrivateDnsConfig cfg, @NonNull List<InetAddress> dnsServers) { this.cfg = cfg; + this.dnsServers = dnsServers; } } }
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java index 05103d9..60bb927 100755 --- a/src/com/android/server/connectivity/NetworkMonitor.java +++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -65,6 +65,8 @@ import static com.android.net.module.util.CollectionUtils.isEmpty; import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA; import static com.android.net.module.util.DeviceConfigUtils.getResBooleanConfig; +import static com.android.net.module.util.FeatureVersions.FEATURE_DDR_IN_CONNECTIVITY; +import static com.android.net.module.util.FeatureVersions.FEATURE_DDR_IN_DNSRESOLVER; import static com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTPS_URL; import static com.android.net.module.util.NetworkStackConstants.TEST_CAPTIVE_PORTAL_HTTP_URL; import static com.android.net.module.util.NetworkStackConstants.TEST_URL_EXPIRATION_TIME; @@ -682,7 +684,10 @@ context, NetworkStackUtils.REEVALUATE_WHEN_RESUME); mAsyncPrivdnsResolutionEnabled = deps.isFeatureEnabled(context, NetworkStackUtils.NETWORKMONITOR_ASYNC_PRIVDNS_RESOLUTION); - mDdrEnabled = deps.isFeatureEnabled(context, NetworkStackUtils.DNS_DDR_VERSION); + mDdrEnabled = mAsyncPrivdnsResolutionEnabled + && deps.isFeatureEnabled(context, NetworkStackUtils.DNS_DDR_VERSION) + && deps.isFeatureSupported(mContext, FEATURE_DDR_IN_CONNECTIVITY) + && deps.isFeatureSupported(mContext, FEATURE_DDR_IN_DNSRESOLVER); mUseHttps = getUseHttpsValidation(); mCaptivePortalUserAgent = getCaptivePortalUserAgent(); mCaptivePortalFallbackSpecs = @@ -719,7 +724,16 @@ mNetworkCapabilities = new NetworkCapabilities(null); mNetworkAgentConfig = NetworkAgentConfigShimImpl.newInstance(null); - mDdrTracker = new DdrTracker(); + // For DdrTracker that can safely update SVCB lookup results itself when the lookup + // completes. The callback is called inline from onAnswer, which is already posted to + // the handler. This ensures that strict mode hostname resolution (which calls + // onQueryDone when processing CMD_PRIVATE_DNS_PROBE_COMPLETED) and SVCB lookup (which calls + // DdrTracker#updateSvcbAnswerAndInvokeUserCallback by posting onAnswer to the Runnable) + // run in order: both of them post exactly once to the handler. + mDdrTracker = new DdrTracker(mCleartextDnsNetwork, mDependencies.getDnsResolver(), + getHandler()::post, + result -> notifyPrivateDnsConfigResolved(result), // Run inline on handler. + mValidationLogs); } /** @@ -1093,6 +1107,7 @@ if (mDdrEnabled) { mDdrTracker.notifyPrivateDnsSettingsChanged(cfg); } + if (!isPrivateDnsValidationRequired() || !cfg.inStrictMode()) { // No DNS resolution required. // @@ -1167,6 +1182,12 @@ if (tst != null) { tst.setLinkProperties(mLinkProperties); } + final boolean dnsInfoUpdated = mDdrEnabled + && mDdrTracker.notifyLinkPropertiesChanged(mLinkProperties); + if (dnsInfoUpdated) { + removeMessages(CMD_EVALUATE_PRIVATE_DNS); + sendMessage(CMD_EVALUATE_PRIVATE_DNS); + } break; case EVENT_NETWORK_CAPABILITIES_CHANGED: handleCapabilitiesChanged((NetworkCapabilities) message.obj, @@ -1650,12 +1671,15 @@ private class EvaluatingPrivateDnsState extends State { private int mPrivateDnsReevalDelayMs; - private PrivateDnsConfig mPrivateDnsConfig; + private PrivateDnsConfig mSyncOnlyPrivateDnsConfig; @Override public void enter() { mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS; - mPrivateDnsConfig = null; + mSyncOnlyPrivateDnsConfig = null; + if (mDdrEnabled) { + mDdrTracker.resetStrictModeHostnameResolutionResult(); + } sendMessage(CMD_EVALUATE_PRIVATE_DNS); } @@ -1663,6 +1687,10 @@ public boolean processMessage(Message msg) { switch (msg.what) { case CMD_EVALUATE_PRIVATE_DNS: { + if (mDdrEnabled) { + mDdrTracker.startSvcbLookup(); + } + if (mAsyncPrivdnsResolutionEnabled) { // Cancel any previously scheduled retry attempt removeMessages(CMD_EVALUATE_PRIVATE_DNS); @@ -1678,12 +1706,13 @@ break; } + // Async resolution not enabled, do a blocking DNS lookup. if (inStrictMode()) { - if (!isStrictModeHostnameResolved(mPrivateDnsConfig)) { + if (!isStrictModeHostnameResolved(mSyncOnlyPrivateDnsConfig)) { resolveStrictModeHostname(); - if (isStrictModeHostnameResolved(mPrivateDnsConfig)) { - notifyPrivateDnsConfigResolved(mPrivateDnsConfig); + if (isStrictModeHostnameResolved(mSyncOnlyPrivateDnsConfig)) { + notifyPrivateDnsConfigResolved(mSyncOnlyPrivateDnsConfig); } else { handlePrivateDnsEvaluationFailure(); // The private DNS probe fails-fast if the server hostname cannot @@ -1742,9 +1771,9 @@ final InetAddress[] ips = DnsUtils.getAllByName(mDependencies.getDnsResolver(), mCleartextDnsNetwork, mPrivateDnsProviderHostname, getDnsProbeTimeout(), str -> validationLog("Strict mode hostname resolution " + str)); - mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); + mSyncOnlyPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); } catch (UnknownHostException uhe) { - mPrivateDnsConfig = null; + mSyncOnlyPrivateDnsConfig = null; } } @@ -1969,11 +1998,16 @@ if (!answer.isEmpty()) { final InetAddress[] ips = answer.toArray(new InetAddress[0]); - final PrivateDnsConfig config = - new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); - notifyPrivateDnsConfigResolved(config); + if (mDdrEnabled) { + mDdrTracker.setStrictModeHostnameResolutionResult(ips); + notifyPrivateDnsConfigResolved(mDdrTracker.getResultForReporting()); + } else { + notifyPrivateDnsConfigResolved( + new PrivateDnsConfig(mPrivateDnsProviderHostname, ips)); + } - validationLog("Strict mode hostname resolution " + elapsedNanos + "ns OK " + validationLog("Strict mode hostname resolution " + + TimeUnit.NANOSECONDS.toMillis(elapsedNanos) + "ms OK " + answer + " for " + mPrivateDnsProviderHostname); transitionTo(mProbingForPrivateDnsState); } else { @@ -2036,7 +2070,7 @@ final String strIps = Objects.toString(answer); validationLog(PROBE_PRIVDNS, queryName, - String.format("%dus: %s", elapsedNanos / 1000, strIps)); + String.format("%dms: %s", TimeUnit.NANOSECONDS.toMillis(elapsedNanos), strIps)); mEvaluationState.noteProbeResult(NETWORK_VALIDATION_PROBE_PRIVDNS, success); if (success) { @@ -3727,6 +3761,10 @@ return DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(context, name); } + boolean isFeatureSupported(@NonNull Context context, long feature) { + return DeviceConfigUtils.isFeatureSupported(context, feature); + } + /** * Collect data stall detection level information for each transport type. Write metrics * data to statsd pipeline.
diff --git a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt index 3bba529..ac78b7a 100644 --- a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt +++ b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager.MATCH_SYSTEM_ONLY import android.net.INetworkStackConnector import android.os.IBinder +import android.os.UserHandle import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import kotlin.test.fail @@ -82,7 +83,15 @@ private fun init() { val bindIntent = Intent(testNetworkStackServiceAction) bindIntent.component = getNetworkStackComponent(bindIntent.action) - context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE) + // Use UserHandle.SYSTEM to bind to the test network stack service as user 0. Otherwise on a + // multi-user device where current user is not user 0, this intent will start another test + // service for the current user which is not expected. + context.bindServiceAsUser( + bindIntent, + serviceConnection, + Context.BIND_AUTO_CREATE, + UserHandle.SYSTEM + ) } fun disconnect() {
diff --git a/tests/integration/root/android/net/ip/IpClientRootTest.kt b/tests/integration/root/android/net/ip/IpClientRootTest.kt index 715e27d..2c7ce17 100644 --- a/tests/integration/root/android/net/ip/IpClientRootTest.kt +++ b/tests/integration/root/android/net/ip/IpClientRootTest.kt
@@ -16,6 +16,7 @@ package android.net.ip +import android.Manifest.permission.INTERACT_ACROSS_USERS_FULL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG import android.Manifest.permission.WRITE_DEVICE_CONFIG @@ -83,7 +84,7 @@ // Connect to the NetworkStack only once, as it is relatively expensive (~50ms plus any // polling time waiting for the test UID to be allowed), and there should be minimal // side-effects between tests compared to reconnecting every time. - automation.adoptShellPermissionIdentity(NETWORK_SETTINGS) + automation.adoptShellPermissionIdentity(NETWORK_SETTINGS, INTERACT_ACROSS_USERS_FULL) try { automation.executeShellCommand("su root service call network_stack " + "$ALLOW_TEST_UID_INDEX i32 " + Process.myUid())
diff --git a/tests/unit/jni/apf_jni.cpp b/tests/unit/jni/apf_jni.cpp index 279e339..873b217 100644 --- a/tests/unit/jni/apf_jni.cpp +++ b/tests/unit/jni/apf_jni.cpp
@@ -36,7 +36,7 @@ uint32_t program_len, uint32_t ram_len, const uint8_t* packet, uint32_t packet_len, uint32_t filter_age) { - if (apf_version == 4) { + if (apf_version <= 4) { return accept_packet((uint8_t*)program, program_len, ram_len, packet, packet_len, filter_age); } else {
diff --git a/tests/unit/src/android/net/apf/ApfFilterTest.kt b/tests/unit/src/android/net/apf/ApfFilterTest.kt index 0aed28f..15ff224 100644 --- a/tests/unit/src/android/net/apf/ApfFilterTest.kt +++ b/tests/unit/src/android/net/apf/ApfFilterTest.kt
@@ -19,6 +19,8 @@ import android.net.LinkAddress import android.net.LinkProperties import android.net.MacAddress +import android.net.NattKeepalivePacketDataParcelable +import android.net.TcpKeepalivePacketDataParcelable import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_NON_IPV4 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_OTHER_HOST import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REPLY_SPA_NO_HOST @@ -29,14 +31,18 @@ import android.net.apf.ApfCounterTracker.Counter.DROPPED_GARP_REPLY import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_ADDR import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_NET -import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_MULTICAST -import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4 +import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_KEEPALIVE_ACK import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_L2_BROADCAST +import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_MULTICAST +import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NATT_KEEPALIVE +import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4 +import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_TCP_PORT7_UNICAST import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MULTICAST_NA import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NON_ICMP_MULTICAST import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_REPLIED_NON_DAD +import android.net.apf.ApfCounterTracker.Counter.PASSED_ETHER_OUR_SRC_MAC import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_BROADCAST_REPLY import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_REQUEST import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_UNICAST_REPLY @@ -50,17 +56,25 @@ import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_SLLA_OPTION import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_TENTATIVE -import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_UNICAST_NON_ICMP import android.net.apf.ApfCounterTracker.Counter.PASSED_MLD import android.net.apf.ApfFilter.Dependencies +import android.net.apf.ApfTestHelpers.Companion.TIMEOUT_MS import android.net.apf.ApfTestHelpers.Companion.consumeInstalledProgram import android.net.apf.ApfTestHelpers.Companion.verifyProgramRun import android.net.apf.BaseApfGenerator.APF_VERSION_3 import android.net.apf.BaseApfGenerator.APF_VERSION_6 import android.net.ip.IpClient.IpClientCallbacksWrapper +import android.net.nsd.NsdManager +import android.net.nsd.OffloadEngine +import android.net.nsd.OffloadServiceInfo import android.os.Build +import android.os.Handler +import android.os.HandlerThread import android.os.SystemClock +import android.system.Os +import android.system.OsConstants.AF_UNIX import android.system.OsConstants.IFA_F_TENTATIVE +import android.system.OsConstants.SOCK_STREAM import androidx.test.filters.SmallTest import com.android.internal.annotations.GuardedBy import com.android.net.module.util.HexDump @@ -81,10 +95,13 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.quitResources +import com.android.testutils.waitForIdle +import java.io.FileDescriptor import java.net.Inet6Address import java.net.InetAddress import kotlin.test.assertContentEquals import kotlin.test.assertEquals +import libcore.io.IoUtils import org.junit.After import org.junit.Before import org.junit.Rule @@ -92,6 +109,9 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong +import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.doAnswer @@ -111,6 +131,7 @@ class ApfFilterTest { companion object { private const val THREAD_QUIT_MAX_RETRY_COUNT = 3 + private const val TAG = "ApfFilterTest" } @get:Rule @@ -124,6 +145,7 @@ @Mock private lateinit var dependencies: Dependencies @Mock private lateinit var ipClientCallback: IpClientCallbacksWrapper + @Mock private lateinit var nsdManager: NsdManager @GuardedBy("mApfFilterCreated") private val mApfFilterCreated = ArrayList<AndroidPacketFilter>() @@ -177,6 +199,12 @@ intArrayOf(0x33, 0x33, 0xff, 0xbb, 0xcc, 0xdd).map { it.toByte() }.toByteArray(), ) + private val handlerThread by lazy { + HandlerThread("$TAG handler thread").apply { start() } + } + private val handler by lazy { Handler(handlerThread.looper) } + private var writerSocket = FileDescriptor() + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -194,6 +222,10 @@ } }.`when`(dependencies).onApfFilterCreated(any()) doReturn(SystemClock.elapsedRealtime()).`when`(dependencies).elapsedRealtime() + val readSocket = FileDescriptor() + Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writerSocket, readSocket) + doReturn(readSocket).`when`(dependencies).createPacketReaderSocket(anyInt()) + doReturn(nsdManager).`when`(context).getSystemService(NsdManager::class.java) } private fun shutdownApfFilters() { @@ -204,7 +236,7 @@ return@quitResources ret } }, { apf: AndroidPacketFilter -> - apf.shutdown() + handler.post { apf.shutdown() } }) synchronized(mApfFilterCreated) { @@ -218,9 +250,13 @@ @After fun tearDown() { + IoUtils.closeQuietly(writerSocket) shutdownApfFilters() + handler.waitForIdle(TIMEOUT_MS) Mockito.framework().clearInlineMocks() ApfJniUtils.resetTransmittedPacketMemory() + handlerThread.quitSafely() + handlerThread.join() } private fun getDefaultConfig(apfVersion: Int = APF_VERSION_6): ApfFilter.ApfConfiguration { @@ -237,16 +273,22 @@ } private fun getApfFilter( - apfCfg: ApfFilter.ApfConfiguration = getDefaultConfig(APF_VERSION_6) + apfCfg: ApfFilter.ApfConfiguration = getDefaultConfig(APF_VERSION_6) ): ApfFilter { - return ApfFilter( - context, - apfCfg, - ifParams, - ipClientCallback, - metrics, - dependencies - ) + lateinit var apfFilter: ApfFilter + handler.post { + apfFilter = ApfFilter( + handler, + context, + apfCfg, + ifParams, + ipClientCallback, + metrics, + dependencies + ) + } + handlerThread.waitForIdle(TIMEOUT_MS) + return apfFilter } private fun doTestEtherTypeAllowListFilter(apfFilter: ApfFilter) { @@ -497,6 +539,26 @@ } @Test + fun testLoopbackFilter() { + val apfConfig = getDefaultConfig() + val apfFilter = getApfFilter(apfConfig) + val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) + // Using scapy to generate echo-ed broadcast packet: + // ether = Ether(src=${ifParams.macAddr}, dst='ff:ff:ff:ff:ff:ff') + // ip = IP(src='192.168.1.1', dst='255.255.255.255', proto=21) + // pkt = ether/ip + val nonDhcpBcastPkt = """ + ffffffffffff020304050607080045000014000100004015b92bc0a80101ffffffff + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + apfFilter.mApfVersionSupported, + program, + HexDump.hexStringToByteArray(nonDhcpBcastPkt), + PASSED_ETHER_OUR_SRC_MAC + ) + } + + @Test fun testIPv4MulticastPacketFilter() { val apfConfig = getDefaultConfig() apfConfig.multicastFilter = true @@ -638,46 +700,267 @@ } @Test - fun testIPv6MulticastPacketFilter() { + fun testIPv4TcpKeepaliveFilter() { + val srcAddr = byteArrayOf(10, 0, 0, 5) + val dstAddr = byteArrayOf(10, 0, 0, 6) + val srcPort = 12345 + val dstPort = 54321 + val seqNum = 2123456789 + val ackNum = 1234567890 + + // src: 10.0.0.5:12345 + // dst: 10.0.0.6:54321 + val parcel = TcpKeepalivePacketDataParcelable() + parcel.srcAddress = InetAddress.getByAddress(srcAddr).address + parcel.srcPort = srcPort + parcel.dstAddress = InetAddress.getByAddress(dstAddr).address + parcel.dstPort = dstPort + parcel.seq = seqNum + parcel.ack = ackNum + val apfConfig = getDefaultConfig() apfConfig.multicastFilter = true + apfConfig.ieee802_3Filter = true val apfFilter = getApfFilter(apfConfig) consumeInstalledProgram(ipClientCallback, installCnt = 2) - val lp = LinkProperties() - for (addr in hostIpv6Addresses) { - lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) - } - apfFilter.setLinkProperties(lp) - val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) + apfFilter.addTcpKeepalivePacketFilter(1, parcel) + var program = consumeInstalledProgram(ipClientCallback, installCnt = 1) - // Using scapy to generate non ICMPv6 sent to ff00::/8 (multicast prefix) packet: + // Drop IPv4 keepalive ack + // Using scapy to generate IPv4 TCP keepalive ack packet with seq + 1: // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") - // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff00::1", nh=59) - // pkt = eth/ip6 - val nonIcmpv6McastPkt = """ - ffffffffffff00112233445586dd6000000000003b4020010000000000000200001a11223344ff00000 - 0000000000000000000000000 + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567890, ack=2123456790) + // pkt = eth/ip/tcp + val keepaliveAckPkt = """ + 01020304050600010203040508004500002800010000400666c50a0000060a000005d4313039499602d2 + 7e916116501020004b4f0000 """.replace("\\s+".toRegex(), "").trim() verifyProgramRun( APF_VERSION_6, program, - HexDump.hexStringToByteArray(nonIcmpv6McastPkt), - DROPPED_IPV6_NON_ICMP_MULTICAST + HexDump.hexStringToByteArray(keepaliveAckPkt), + DROPPED_IPV4_KEEPALIVE_ACK ) - // Using scapy to generate non ICMPv6 unicast packet: + // Pass IPv4 non-keepalive ack from the same source address + // Using scapy to generate IPv4 TCP non-keepalive ack from the same source address: // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") - // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:5566", nh=59) - // pkt = eth/ip6 - val nonIcmpv6UcastPkt = """ - ffffffffffff00112233445586dd6000000000003b4020010000000000000200001a112233442001000 - 0000000000200001a33445566 + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567990, ack=2123456789) + // pkt = eth/ip/tcp + val nonKeepaliveAckPkt1 = """ + 01020304050600010203040508004500002800010000400666c50a0000060a000005d431303949960336 + 7e916115501020004aec0000 """.replace("\\s+".toRegex(), "").trim() verifyProgramRun( APF_VERSION_6, program, - HexDump.hexStringToByteArray(nonIcmpv6UcastPkt), - PASSED_IPV6_UNICAST_NON_ICMP + HexDump.hexStringToByteArray(nonKeepaliveAckPkt1), + PASSED_IPV4_UNICAST + ) + + // Pass IPv4 non-keepalive ack from the same source address + // Using scapy to generate IPv4 TCP non-keepalive ack from the same source address: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567890, ack=2123456790) + // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') + // pkt = eth/ip/tcp/payload + val nonKeepaliveAckPkt2 = """ + 01020304050600010203040508004500003200010000400666bb0a0000060a000005d4313039499602d27 + e91611650102000372c000000010203040506070809 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(nonKeepaliveAckPkt2), + PASSED_IPV4_UNICAST + ) + + // Pass IPv4 keepalive ack from another address + // Using scapy to generate IPv4 TCP keepalive ack from another address: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.7', dst='10.0.0.5') + // tcp = TCP(sport=23456, dport=65432, flags="A", seq=2123456780, ack=1123456789) + // pkt = eth/ip/tcp + val otherSrcKeepaliveAck = """ + 01020304050600010203040508004500002800010000400666c40a0000070a0000055ba0ff987e91610c4 + 2f697155010200066e60000 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(otherSrcKeepaliveAck), + PASSED_IPV4_UNICAST + ) + + // test IPv4 packets when TCP keepalive filter is removed + apfFilter.removeKeepalivePacketFilter(1) + program = consumeInstalledProgram(ipClientCallback, installCnt = 1) + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(keepaliveAckPkt), + PASSED_IPV4_UNICAST + ) + + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(otherSrcKeepaliveAck), + PASSED_IPV4_UNICAST + ) + } + + @Test + fun testIPv4NattKeepaliveFilter() { + val srcAddr = byteArrayOf(10, 0, 0, 5) + val dstAddr = byteArrayOf(10, 0, 0, 6) + val srcPort = 1024 + val dstPort = 4500 + + // src: 10.0.0.5:1024 + // dst: 10.0.0.6:4500 + val parcel = NattKeepalivePacketDataParcelable() + parcel.srcAddress = InetAddress.getByAddress(srcAddr).address + parcel.srcPort = srcPort + parcel.dstAddress = InetAddress.getByAddress(dstAddr).address + parcel.dstPort = dstPort + + val apfConfig = getDefaultConfig() + apfConfig.multicastFilter = true + apfConfig.ieee802_3Filter = true + val apfFilter = getApfFilter(apfConfig) + consumeInstalledProgram(ipClientCallback, installCnt = 2) + apfFilter.addNattKeepalivePacketFilter(1, parcel) + val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) + + // Drop IPv4 keepalive response packet + // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xff: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // udp = UDP(sport=4500, dport=1024) + // payload = NAT_KEEPALIVE(nat_keepalive=0xff) + // pkt = eth/ip/udp/payload + val validNattPkt = """ + 01020304050600010203040508004500001d00010000401166c50a0000060a000005119404000009d73cff + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(validNattPkt), + DROPPED_IPV4_NATT_KEEPALIVE + ) + + // Pass IPv4 keepalive response packet with 0xfe payload + // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // udp = UDP(sport=4500, dport=1024) + // payload = NAT_KEEPALIVE(nat_keepalive=0xfe) + // pkt = eth/ip/udp/payload + val invalidNattPkt = """ + 01020304050600010203040508004500001d00010000401166c50a0000060a000005119404000009d83cfe + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(invalidNattPkt), + PASSED_IPV4_UNICAST + ) + + // Pass IPv4 non-keepalive response packet from the same source address + // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // udp = UDP(sport=4500, dport=1024) + // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') + // pkt = eth/ip/udp/payload + val nonNattPkt = """ + 01020304050600010203040508004500002600010000401166bc0a0000060a000005119404000012c2120 + 0010203040506070809 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(nonNattPkt), + PASSED_IPV4_UNICAST + ) + + // Pass IPv4 non-keepalive response packet from other source address + // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.7', dst='10.0.0.5') + // udp = UDP(sport=4500, dport=1024) + // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') + // pkt = eth/ip/udp/payload + val otherSrcNonNattPkt = """ + 01020304050600010203040508004500002600010000401166bb0a0000070a000005119404000012c2110 + 0010203040506070809 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(otherSrcNonNattPkt), + PASSED_IPV4_UNICAST + ) + } + + @Test + fun testIPv4TcpPort7Filter() { + val apfFilter = getApfFilter() + val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) + + // Drop IPv4 TCP port 7 packet + // Using scapy to generate IPv4 TCP port 7 packet: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5') + // tcp = TCP(dport=7) + // pkt = eth/ip/tcp + val tcpPort7Pkt = """ + 01020304050600010203040508004500002800010000400666c50a0000060a00000500140007000000000 + 0000000500220007bbd0000 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(tcpPort7Pkt), + DROPPED_IPV4_TCP_PORT7_UNICAST + ) + + // Pass IPv4 TCP initial fragment packet + // Using scapy to generate IPv4 TCP initial fragment packet: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5', flags=1, frag=0) + // tcp = TCP() + // pkt = eth/ip/tcp + val initialFragmentTcpPkt = """ + 01020304050600010203040508004500002800012000400646c50a0000060a00000500140050000000000 + 0000000500220007b740000 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(initialFragmentTcpPkt), + PASSED_IPV4 + ) + + // Pass IPv4 TCP fragment packet + // Using scapy to generate IPv4 TCP fragment packet: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // ip = IP(src='10.0.0.6', dst='10.0.0.5', flags=1, frag=100) + // tcp = TCP() + // pkt = eth/ip/tcp + val fragmentTcpPkt = """ + 01020304050600010203040508004500002800012064400646610a0000060a00000500140050000000000 + 0000000500220007b740000 + """.replace("\\s+".toRegex(), "").trim() + verifyProgramRun( + APF_VERSION_6, + program, + HexDump.hexStringToByteArray(fragmentTcpPkt), + PASSED_IPV4 ) } @@ -1739,6 +2022,63 @@ } } + @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Test + fun testRegisterOffloadEngine() { + val apfConfig = getDefaultConfig() + apfConfig.shouldHandleMdnsOffload = true + val apfFilter = getApfFilter(apfConfig) + val captor = ArgumentCaptor.forClass(OffloadEngine::class.java) + verify(nsdManager).registerOffloadEngine( + eq(ifParams.name), + anyLong(), + anyLong(), + any(), + captor.capture() + ) + val offloadEngine = captor.value + val info1 = OffloadServiceInfo( + OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"), + listOf(), + "Android_test.local", + byteArrayOf(0x01, 0x02, 0x03, 0x04), + 0, + OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() + ) + val info2 = OffloadServiceInfo( + OffloadServiceInfo.Key("TestServiceName2", "_advertisertest._tcp"), + listOf(), + "Android_test.local", + byteArrayOf(0x01, 0x02, 0x03, 0x04), + 0, + OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() + ) + val updatedInfo1 = OffloadServiceInfo( + OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"), + listOf(), + "Android_test.local", + byteArrayOf(), + 0, + OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() + ) + handler.post { offloadEngine.onOffloadServiceUpdated(info1) } + handlerThread.waitForIdle(TIMEOUT_MS) + assertContentEquals(listOf(info1), apfFilter.mOffloadServiceInfos) + handler.post { offloadEngine.onOffloadServiceUpdated(info2) } + handlerThread.waitForIdle(TIMEOUT_MS) + assertContentEquals(listOf(info1, info2), apfFilter.mOffloadServiceInfos) + handler.post { offloadEngine.onOffloadServiceUpdated(updatedInfo1) } + handlerThread.waitForIdle(TIMEOUT_MS) + assertContentEquals(listOf(info2, updatedInfo1), apfFilter.mOffloadServiceInfos) + handler.post { offloadEngine.onOffloadServiceRemoved(updatedInfo1) } + handlerThread.waitForIdle(TIMEOUT_MS) + assertContentEquals(listOf(info2), apfFilter.mOffloadServiceInfos) + + handler.post { apfFilter.shutdown() } + handlerThread.waitForIdle(TIMEOUT_MS) + verify(nsdManager).unregisterOffloadEngine(any()) + } + @Test fun testApfProgramUpdate() { val apfFilter = getApfFilter() @@ -1794,4 +2134,13 @@ val program = programCaptor.allValues.first() assertContentEquals(ByteArray(4096) { 0 }, program) } + + @Test + fun testApfFilterResumeWillCleanUpTheApfMemoryRegion() { + val apfFilter = getApfFilter() + consumeInstalledProgram(ipClientCallback, installCnt = 2) + apfFilter.resume() + val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) + assertContentEquals(ByteArray(4096) { 0 }, program) + } }
diff --git a/tests/unit/src/android/net/apf/ApfGeneratorTest.kt b/tests/unit/src/android/net/apf/ApfGeneratorTest.kt index 60f0ca8..98b2a42 100644 --- a/tests/unit/src/android/net/apf/ApfGeneratorTest.kt +++ b/tests/unit/src/android/net/apf/ApfGeneratorTest.kt
@@ -512,7 +512,7 @@ program ) assertContentEquals( - listOf("0: drop counter=46"), + listOf("0: drop counter=47"), ApfJniUtils.disassembleApf(program).map { it.trim() } ) @@ -561,14 +561,14 @@ byteArrayOf( encodeInstruction(opcode = 14, immLength = 2, register = 1), 1, 0 ) + largeByteArray + byteArrayOf( - encodeInstruction(opcode = 21, immLength = 1, register = 0), 48, 6, 13 + encodeInstruction(opcode = 21, immLength = 1, register = 0), 48, 6, 9 ), program ) assertContentEquals( listOf( "0: data 256, " + "01".repeat(256), - "259: debugbuf size=1549" + "259: debugbuf size=1545" ), ApfJniUtils.disassembleApf(program).map { it.trim() } ) @@ -854,7 +854,7 @@ .generate() assertContentEquals(listOf( "0: data 9, 112233445566778899", - "12: debugbuf size=1776", + "12: debugbuf size=1772", "16: allocate 18", "20: datacopy src=3, len=6", "23: datacopy src=4, len=3",
diff --git a/tests/unit/src/android/net/apf/ApfTest.java b/tests/unit/src/android/net/apf/ApfTest.java index 3db7a7f..14e2122 100644 --- a/tests/unit/src/android/net/apf/ApfTest.java +++ b/tests/unit/src/android/net/apf/ApfTest.java
@@ -17,6 +17,7 @@ package android.net.apf; import static android.net.apf.ApfCounterTracker.Counter.getCounterEnumFromOffset; +import static android.net.apf.ApfTestHelpers.TIMEOUT_MS; import static android.net.apf.ApfTestHelpers.consumeInstalledProgram; import static android.net.apf.ApfTestHelpers.DROP; import static android.net.apf.ApfTestHelpers.MIN_PKT_SIZE; @@ -41,7 +42,6 @@ import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_IPV6; -import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_STREAM; @@ -57,12 +57,11 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.BroadcastReceiver; import android.content.Context; @@ -72,14 +71,14 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; -import android.net.NattKeepalivePacketDataParcelable; -import android.net.TcpKeepalivePacketDataParcelable; import android.net.apf.ApfCounterTracker.Counter; import android.net.apf.ApfFilter.ApfConfiguration; import android.net.apf.BaseApfGenerator.IllegalInstructionException; import android.net.ip.IpClient; import android.net.metrics.IpConnectivityLog; import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; import android.os.PowerManager; import android.os.SystemClock; import android.stats.connectivity.NetworkQuirkEvent; @@ -109,6 +108,7 @@ import com.android.testutils.ConcurrentUtils; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.HandlerUtils; import libcore.io.IoUtils; import libcore.io.Streams; @@ -130,6 +130,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Inet4Address; import java.net.Inet6Address; @@ -142,6 +143,7 @@ import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.atomic.AtomicReference; /** * Tests for APF program generator and interpreter. @@ -178,10 +180,9 @@ @Mock private IpClient.IpClientCallbacksWrapper mIpClientCb; @GuardedBy("mApfFilterCreated") private final ArrayList<AndroidPacketFilter> mApfFilterCreated = new ArrayList<>(); - @GuardedBy("mThreadsToBeCleared") - private final ArrayList<Thread> mThreadsToBeCleared = new ArrayList<>(); - private FileDescriptor mWriteSocket; + private HandlerThread mHandlerThread; + private Handler mHandler; private long mCurrentTimeMs; @Before @@ -190,39 +191,22 @@ doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); doReturn(mApfSessionInfoMetrics).when(mDependencies).getApfSessionInfoMetrics(); doReturn(mIpClientRaInfoMetrics).when(mDependencies).getIpClientRaInfoMetrics(); + FileDescriptor readSocket = new FileDescriptor(); + mWriteSocket = new FileDescriptor(); + Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket); + doReturn(readSocket).when(mDependencies).createPacketReaderSocket(anyInt()); + mCurrentTimeMs = SystemClock.elapsedRealtime(); + doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime(); + doReturn(true).when(mIpClientCb).installPacketFilter(any()); doAnswer((invocation) -> { synchronized (mApfFilterCreated) { mApfFilterCreated.add(invocation.getArgument(0)); } return null; }).when(mDependencies).onApfFilterCreated(any()); - doAnswer((invocation) -> { - synchronized (mThreadsToBeCleared) { - mThreadsToBeCleared.add(invocation.getArgument(0)); - } - return null; - }).when(mDependencies).onThreadCreated(any()); - FileDescriptor readSocket = new FileDescriptor(); - mWriteSocket = new FileDescriptor(); - Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket); - doReturn(readSocket).when(mDependencies).createRaReaderSocket(anyInt()); - mCurrentTimeMs = SystemClock.elapsedRealtime(); - doReturn(mCurrentTimeMs).when(mDependencies).elapsedRealtime(); - doReturn(true).when(mIpClientCb).installPacketFilter(any()); - } - - private void quitThreads() throws Exception { - ConcurrentUtils.quitThreads( - THREAD_QUIT_MAX_RETRY_COUNT, - false /* interrupt */, - TIMEOUT_MS, - () -> { - synchronized (mThreadsToBeCleared) { - final ArrayList<Thread> ret = new ArrayList<>(mThreadsToBeCleared); - mThreadsToBeCleared.clear(); - return ret; - } - }); + mHandlerThread = new HandlerThread("ApfTestThread"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); } private void shutdownApfFilters() throws Exception { @@ -233,26 +217,22 @@ mApfFilterCreated.clear(); return ret; } - }, (apf) -> { - apf.shutdown(); - }); + }, (apf) -> mHandler.post(apf::shutdown)); synchronized (mApfFilterCreated) { assertEquals("ApfFilters did not fully shutdown.", 0, mApfFilterCreated.size()); } - // It's necessary to wait until all ReceiveThreads have finished running because - // clearInlineMocks clears all Mock objects, including some privilege frameworks - // required by logStats, at the end of ReceiveThread#run. - quitThreads(); } @After public void tearDown() throws Exception { + IoUtils.closeQuietly(mWriteSocket); shutdownApfFilters(); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); // Clear mocks to prevent from stubs holding instances and cause memory leaks. Mockito.framework().clearInlineMocks(); - IoUtils.closeQuietly(mWriteSocket); - mWriteSocket = null; + mHandlerThread.quitSafely(); + mHandlerThread.join(); } private static final String TAG = "ApfTest"; @@ -267,7 +247,6 @@ private static final int MIN_RDNSS_LIFETIME_SEC = 0; private static final int MIN_METRICS_SESSION_DURATIONS_MS = 300_000; - private static final int TIMEOUT_MS = 1000; private static final int NO_CALLBACK_TIMEOUT_MS = 500; private static final int THREAD_QUIT_MAX_RETRY_COUNT = 3; @@ -1035,10 +1014,19 @@ } private void pretendPacketReceived(byte[] packet) - throws IOException, ErrnoException { + throws InterruptedIOException, ErrnoException { Os.write(mWriteSocket, packet, 0, packet.length); } + private ApfFilter getApfFilter(ApfFilter.ApfConfiguration config) { + AtomicReference<ApfFilter> apfFilter = new AtomicReference<>(); + mHandler.post(() -> + apfFilter.set(new ApfFilter(mHandler, mContext, config, TEST_PARAMS, + mIpClientCb, mNetworkQuirkMetrics, mDependencies))); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); + return apfFilter.get(); + } + /** * Generate APF program, run pcap file though APF filter, then check all the packets in the file * should be dropped. @@ -1056,8 +1044,7 @@ config.apfRamSize = 1700; config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, - mIpClientCb, mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 2 /* installCnt */); apfFilter.setLinkProperties(lp); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); @@ -1084,25 +1071,12 @@ private static final int IP_HEADER_OFFSET = ETH_HEADER_LEN; private static final int IPV4_HEADER_LEN = 20; - private static final int IPV4_TOTAL_LENGTH_OFFSET = IP_HEADER_OFFSET + 2; private static final int IPV4_PROTOCOL_OFFSET = IP_HEADER_OFFSET + 9; - private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12; private static final int IPV4_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 16; - private static final int IPV4_TCP_HEADER_LEN = 20; private static final int IPV4_TCP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN; - private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0; - private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2; - private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4; - private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8; - private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12; - private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13; private static final int IPV4_UDP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN; - private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0; - private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2; - private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4; - private static final int IPV4_UDP_PAYLOAD_OFFSET = IPV4_UDP_HEADER_OFFSET + 8; private static final byte[] IPV4_BROADCAST_ADDRESS = {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; @@ -1112,10 +1086,6 @@ private static final int IPV6_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 8; private static final int IPV6_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 24; private static final int IPV6_PAYLOAD_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN; - private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 0; - private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 2; - private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_PAYLOAD_OFFSET + 4; - private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_PAYLOAD_OFFSET + 8; // The IPv6 all nodes address ff02::1 private static final byte[] IPV6_ALL_NODES_ADDRESS = { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; @@ -1129,25 +1099,18 @@ private static final int ICMP6_TYPE_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN; private static final int ICMP6_ROUTER_SOLICITATION = 133; private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; - private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; private static final int ICMP6_RA_HEADER_LEN = 16; private static final int ICMP6_RA_CHECKSUM_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2; - private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = - IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6; private static final int ICMP6_RA_REACHABLE_TIME_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8; - private static final int ICMP6_RA_RETRANSMISSION_TIMER_OFFSET = - IP_HEADER_OFFSET + IPV6_HEADER_LEN + 12; private static final int ICMP6_RA_OPTION_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; private static final int ICMP6_PREFIX_OPTION_TYPE = 3; private static final int ICMP6_PREFIX_OPTION_LEN = 32; - private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; - private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; // From RFC6106: Recursive DNS Server option private static final int ICMP6_RDNSS_OPTION_TYPE = 25; @@ -1158,8 +1121,6 @@ private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; // Above three options all have the same format: private static final int ICMP6_4_BYTE_OPTION_LEN = 8; - private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; - private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; private static final int UDP_HEADER_LEN = 8; private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22; @@ -1197,7 +1158,6 @@ private static final byte[] IPV4_MDNS_MULTICAST_ADDR = {(byte) 224, 0, 0, (byte) 251}; private static final byte[] IPV6_MDNS_MULTICAST_ADDR = {(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfb}; - private static final int IPV6_UDP_DEST_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 2; private static final int MDNS_UDP_PORT = 5353; private static void setIpv4VersionFields(ByteBuffer packet) { @@ -1232,8 +1192,7 @@ ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, - mIpClientCb, mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); apfFilter.setLinkProperties(lp); @@ -1288,8 +1247,7 @@ @Test public void testApfFilterIPv6() throws Exception { ApfConfiguration config = getDefaultConfig(); - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify empty IPv6 packet is passed @@ -1702,8 +1660,7 @@ ApfConfiguration config = getDefaultConfig(); config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); apfFilter.setLinkProperties(lp); @@ -1762,10 +1719,9 @@ config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; clearInvocations(mIpClientCb); - apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter2 = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - apfFilter.setLinkProperties(lp); + apfFilter2.setLinkProperties(lp); program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); assertDrop(program, mcastv4packet.array()); assertDrop(program, mcastv6packet.array()); @@ -1790,8 +1746,7 @@ private void doTestApfFilterMulticastPingWhileDozing(boolean isLightDozing) throws Exception { final ApfConfiguration configuration = getDefaultConfig(); - final ApfFilter apfFilter = new ApfFilter(mContext, configuration, TEST_PARAMS, - mIpClientCb, mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(configuration); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final ArgumentCaptor<BroadcastReceiver> receiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); @@ -1847,8 +1802,7 @@ @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public void testApfFilter802_3() throws Exception { ApfConfiguration config = getDefaultConfig(); - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify empty packet of 100 zero bytes is passed @@ -1866,8 +1820,7 @@ // Now turn on the filter config.ieee802_3Filter = DROP_802_3_FRAMES; - apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + apfFilter = getApfFilter(config); program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify that IEEE802.3 frame is dropped @@ -1892,8 +1845,7 @@ final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6}; ApfConfiguration config = getDefaultConfig(); - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify empty packet of 100 zero bytes is passed @@ -1911,8 +1863,7 @@ // Now add IPv4 to the black list config.ethTypeBlackList = ipv4BlackList; - apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + apfFilter = getApfFilter(config); program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify that IPv4 frame will be dropped @@ -1925,8 +1876,7 @@ // Now let us have both IPv4 and IPv6 in the black list config.ethTypeBlackList = ipv4Ipv6BlackList; - apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + apfFilter = getApfFilter(config); program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify that IPv4 frame will be dropped @@ -1964,8 +1914,7 @@ ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Verify initially ARP request filter is off, and GARP filter is on. @@ -2012,281 +1961,9 @@ return packet.array(); } - private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5}; - private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6}; - private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7}; - private static final byte[] IPV6_KEEPALIVE_SRC_ADDR = - {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1}; - private static final byte[] IPV6_KEEPALIVE_DST_ADDR = - {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2}; private static final byte[] IPV6_ANOTHER_ADDR = {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5}; - @Test - public void testApfFilterKeepaliveAck() throws Exception { - final ApfConfiguration config = getDefaultConfig(); - config.multicastFilter = DROP_MULTICAST; - config.ieee802_3Filter = DROP_802_3_FRAMES; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); - consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - byte[] program; - final int srcPort = 12345; - final int dstPort = 54321; - final int seqNum = 2123456789; - final int ackNum = 1234567890; - final int anotherSrcPort = 23456; - final int anotherDstPort = 65432; - final int anotherSeqNum = 2123456780; - final int anotherAckNum = 1123456789; - final int slot1 = 1; - final int slot2 = 2; - final int window = 14480; - final int windowScale = 4; - - // src: 10.0.0.5, port: 12345 - // dst: 10.0.0.6, port: 54321 - InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR); - InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR); - - final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); - parcel.srcAddress = srcAddr.getAddress(); - parcel.srcPort = srcPort; - parcel.dstAddress = dstAddr.getAddress(); - parcel.dstPort = dstPort; - parcel.seq = seqNum; - parcel.ack = ackNum; - - apfFilter.addTcpKeepalivePacketFilter(slot1, parcel); - program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - - // Verify IPv4 keepalive ack packet is dropped - // src: 10.0.0.6, port: 54321 - // dst: 10.0.0.5, port: 12345 - assertDrop(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); - // Verify IPv4 non-keepalive ack packet from the same source address is passed - assertPass(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */)); - assertPass(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */)); - // Verify IPv4 packet from another address is passed - assertPass(program, - ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); - - // Remove IPv4 keepalive filter - apfFilter.removeKeepalivePacketFilter(slot1); - program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - - try { - // src: 2404:0:0:0:0:0:faf1, port: 12345 - // dst: 2404:0:0:0:0:0:faf2, port: 54321 - srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR); - dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR); - - final TcpKeepalivePacketDataParcelable ipv6Parcel = - new TcpKeepalivePacketDataParcelable(); - ipv6Parcel.srcAddress = srcAddr.getAddress(); - ipv6Parcel.srcPort = srcPort; - ipv6Parcel.dstAddress = dstAddr.getAddress(); - ipv6Parcel.dstPort = dstPort; - ipv6Parcel.seq = seqNum; - ipv6Parcel.ack = ackNum; - - apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel); - program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - - // Verify IPv6 keepalive ack packet is dropped - // src: 2404:0:0:0:0:0:faf2, port: 54321 - // dst: 2404:0:0:0:0:0:faf1, port: 12345 - assertDrop(program, - ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1)); - // Verify IPv6 non-keepalive ack packet from the same source address is passed - assertPass(program, - ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum + 100, seqNum)); - // Verify IPv6 packet from another address is passed - assertPass(program, - ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum)); - - // Remove IPv6 keepalive filter - apfFilter.removeKeepalivePacketFilter(slot1); - - // Verify multiple filters - apfFilter.addTcpKeepalivePacketFilter(slot1, parcel); - apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel); - program = consumeInstalledProgram(mIpClientCb, 3 /* installCnt */); - - // Verify IPv4 keepalive ack packet is dropped - // src: 10.0.0.6, port: 54321 - // dst: 10.0.0.5, port: 12345 - assertDrop(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); - // Verify IPv4 non-keepalive ack packet from the same source address is passed - assertPass(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */)); - // Verify IPv4 packet from another address is passed - assertPass(program, - ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); - - // Verify IPv6 keepalive ack packet is dropped - // src: 2404:0:0:0:0:0:faf2, port: 54321 - // dst: 2404:0:0:0:0:0:faf1, port: 12345 - assertDrop(program, - ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1)); - // Verify IPv6 non-keepalive ack packet from the same source address is passed - assertPass(program, - ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum + 100, seqNum)); - // Verify IPv6 packet from another address is passed - assertPass(program, - ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort, - anotherDstPort, anotherSeqNum, anotherAckNum)); - - // Remove keepalive filters - apfFilter.removeKeepalivePacketFilter(slot1); - apfFilter.removeKeepalivePacketFilter(slot2); - } catch (UnsupportedOperationException e) { - // TODO: support V6 packets - } - - // Verify IPv4, IPv6 packets are passed - assertPass(program, - ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); - assertPass(program, - ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, ackNum, seqNum + 1)); - assertPass(program, - ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort, - dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); - assertPass(program, - ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort, - dstPort, anotherSeqNum, anotherAckNum)); - } - - private static byte[] ipv4TcpPacket(byte[] sip, byte[] dip, int sport, - int dport, int seq, int ack, int dataLength) { - final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN; - - ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]); - - // Ethertype and IPv4 header - setIpv4VersionFields(packet); - packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); - packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP); - put(packet, IPV4_SRC_ADDR_OFFSET, sip); - put(packet, IPV4_DEST_ADDR_OFFSET, dip); - packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport); - packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport); - packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq); - packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack); - - // TCP header length 5(20 bytes), reserved 3 bits, NS=0 - packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50); - // TCP flags: ACK set - packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10); - return packet.array(); - } - - private static byte[] ipv6TcpPacket(byte[] sip, byte[] tip, int sport, - int dport, int seq, int ack) { - ByteBuffer packet = ByteBuffer.wrap(new byte[100]); - setIpv6VersionFields(packet); - packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_TCP); - put(packet, IPV6_SRC_ADDR_OFFSET, sip); - put(packet, IPV6_DEST_ADDR_OFFSET, tip); - packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport); - packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport); - packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq); - packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack); - return packet.array(); - } - - @Test - public void testApfFilterNattKeepalivePacket() throws Exception { - final ApfConfiguration config = getDefaultConfig(); - config.multicastFilter = DROP_MULTICAST; - config.ieee802_3Filter = DROP_802_3_FRAMES; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); - consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - byte[] program; - final int srcPort = 1024; - final int dstPort = 4500; - final int slot1 = 1; - // NAT-T keepalive - final byte[] kaPayload = {(byte) 0xff}; - final byte[] nonKaPayload = {(byte) 0xfe}; - - // src: 10.0.0.5, port: 1024 - // dst: 10.0.0.6, port: 4500 - InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR); - InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR); - - final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); - parcel.srcAddress = srcAddr.getAddress(); - parcel.srcPort = srcPort; - parcel.dstAddress = dstAddr.getAddress(); - parcel.dstPort = dstPort; - - apfFilter.addNattKeepalivePacketFilter(slot1, parcel); - program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); - - // Verify IPv4 keepalive packet is dropped - // src: 10.0.0.6, port: 4500 - // dst: 10.0.0.5, port: 1024 - byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, - IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */); - System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length); - assertDrop(program, pkt); - - // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter. - System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length); - assertPass(program, pkt); - - // Verify IPv4 non-keepalive response packet from the same source address is passed - assertPass(program, - ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, 10 /* dataLength */)); - - // Verify IPv4 non-keepalive response packet from other source address is passed - assertPass(program, - ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, - dstPort, srcPort, 10 /* dataLength */)); - - apfFilter.removeKeepalivePacketFilter(slot1); - } - - private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport, - int dport, int dataLength) { - final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN; - final int udpLength = UDP_HEADER_LEN + dataLength; - ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]); - - // Ethertype and IPv4 header - setIpv4VersionFields(packet); - packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); - packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP); - put(packet, IPV4_SRC_ADDR_OFFSET, sip); - put(packet, IPV4_DEST_ADDR_OFFSET, dip); - packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport); - packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport); - packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength); - - return packet.array(); - } - private static class RaPacketBuilder { final ByteArrayOutputStream mPacket = new ByteArrayOutputStream(); int mFlowLabel = 0x12345; @@ -2467,8 +2144,7 @@ @Test public void testRaToString() throws Exception { ApfConfiguration config = getDefaultConfig(); - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] packet = buildLargeRa(); ApfFilter.Ra ra = apfFilter.new Ra(packet, packet.length); @@ -2541,8 +2217,7 @@ ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final int ROUTER_LIFETIME = 1000; @@ -2626,8 +2301,7 @@ final ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final int RA_REACHABLE_TIME = 1800; final int RA_RETRANSMISSION_TIMER = 1234; @@ -2667,8 +2341,7 @@ final ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final int routerLifetime = 1000; @@ -2740,8 +2413,7 @@ ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); for (int i = 0; i < 1000; i++) { byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; r.nextBytes(packet); @@ -2761,8 +2433,7 @@ ApfConfiguration config = getDefaultConfig(); config.multicastFilter = DROP_MULTICAST; config.ieee802_3Filter = DROP_802_3_FRAMES; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); for (int i = 0; i < 1000; i++) { byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; r.nextBytes(packet); @@ -2776,8 +2447,7 @@ @Test public void testMatchedRaUpdatesLifetime() throws Exception { - final ApfFilter apfFilter = new ApfFilter(mContext, getDefaultConfig(), TEST_PARAMS, - mIpClientCb, mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(getDefaultConfig()); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an RA and build an APF program @@ -2801,8 +2471,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Template packet: // Frame 1: 150 bytes on wire (1200 bits), 150 bytes captured (1200 bits) @@ -2866,8 +2535,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -2895,8 +2563,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -2931,8 +2598,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -2960,8 +2626,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -2997,8 +2662,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -3030,8 +2694,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -3069,8 +2732,7 @@ // configure accept_ra_min_lft final ApfConfiguration config = getDefaultConfig(); config.acceptRaMinLft = 180; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); // Create an initial RA and build an APF program @@ -3142,8 +2804,8 @@ public void testInstallPacketFilterFailure() throws Exception { doReturn(false).when(mIpClientCb).installPacketFilter(any()); final ApfConfiguration config = getDefaultConfig(); - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); + verify(mNetworkQuirkMetrics).setEvent(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); verify(mNetworkQuirkMetrics).statsWrite(); reset(mNetworkQuirkMetrics); @@ -3160,8 +2822,7 @@ final ApfConfiguration config = getDefaultConfig(); config.apfVersionSupported = 2; config.apfRamSize = 512; - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final byte[] ra = buildLargeRa(); pretendPacketReceived(ra); @@ -3172,12 +2833,14 @@ } @Test - public void testGenerateApfProgramException() throws Exception { + public void testGenerateApfProgramException() { final ApfConfiguration config = getDefaultConfig(); - ApfFilter apfFilter = spy(new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies)); + ApfFilter apfFilter = getApfFilter(config); + // Simulate exception during installNewProgramLocked() by mocking + // mDependencies.elapsedRealtime() to throw an exception (this method doesn't throw in + // real-world scenarios). + doThrow(new IllegalStateException("test exception")).when(mDependencies).elapsedRealtime(); synchronized (apfFilter) { - when(apfFilter.emitPrologueLocked()).thenThrow(new IllegalStateException("test")); apfFilter.installNewProgramLocked(); } verify(mNetworkQuirkMetrics).setEvent(NetworkQuirkEvent.QE_APF_GENERATE_FILTER_EXCEPTION); @@ -3192,8 +2855,7 @@ final long startTimeMs = 12345; final long durationTimeMs = config.minMetricsSessionDurationMs; doReturn(startTimeMs).when(mDependencies).elapsedRealtime(); - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); byte[] program = consumeInstalledProgram(mIpClientCb, 2 /* installCnt */); int maxProgramSize = 0; int numProgramUpdated = 0; @@ -3238,7 +2900,9 @@ // Write metrics data to statsd pipeline when shutdown. doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime(); - apfFilter.shutdown(); + mHandler.post(apfFilter::shutdown); + IoUtils.closeQuietly(mWriteSocket); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); verify(mApfSessionInfoMetrics).setVersion(4); verify(mApfSessionInfoMetrics).setMemorySize(4096); @@ -3270,8 +2934,7 @@ final long startTimeMs = 12345; final long durationTimeMs = config.minMetricsSessionDurationMs; doReturn(startTimeMs).when(mDependencies).elapsedRealtime(); - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); consumeInstalledProgram(mIpClientCb, 1 /* installCnt */); final int routerLifetime = 1000; @@ -3327,7 +2990,9 @@ // Write metrics data to statsd pipeline when shutdown. doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime(); - apfFilter.shutdown(); + mHandler.post(apfFilter::shutdown); + IoUtils.closeQuietly(mWriteSocket); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); // Verify each metric fields in IpClientRaInfoMetrics. verify(mIpClientRaInfoMetrics).setMaxNumberOfDistinctRas(6); @@ -3348,20 +3013,20 @@ // Verify no metrics data written to statsd for duration less than durationTimeMs. doReturn(startTimeMs).when(mDependencies).elapsedRealtime(); - final ApfFilter apfFilter = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter = getApfFilter(config); doReturn(startTimeMs + durationTimeMs - 1).when(mDependencies).elapsedRealtime(); - apfFilter.shutdown(); + mHandler.post(apfFilter::shutdown); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); verify(mApfSessionInfoMetrics, never()).statsWrite(); verify(mIpClientRaInfoMetrics, never()).statsWrite(); // Verify metrics data written to statsd for duration greater than or equal to // durationTimeMs. doReturn(startTimeMs).when(mDependencies).elapsedRealtime(); - final ApfFilter apfFilter2 = new ApfFilter(mContext, config, TEST_PARAMS, mIpClientCb, - mNetworkQuirkMetrics, mDependencies); + final ApfFilter apfFilter2 = getApfFilter(config); doReturn(startTimeMs + durationTimeMs).when(mDependencies).elapsedRealtime(); - apfFilter2.shutdown(); + mHandler.post(apfFilter2::shutdown); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); verify(mApfSessionInfoMetrics).statsWrite(); verify(mIpClientRaInfoMetrics).statsWrite(); }
diff --git a/tests/unit/src/android/net/ip/ConnectivityPacketTrackerTest.kt b/tests/unit/src/android/net/ip/ConnectivityPacketTrackerTest.kt new file mode 100644 index 0000000..1ee0ca5 --- /dev/null +++ b/tests/unit/src/android/net/ip/ConnectivityPacketTrackerTest.kt
@@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.ip + +import android.net.MacAddress +import android.net.ip.ConnectivityPacketTracker.Dependencies +import android.os.Handler +import android.os.HandlerThread +import android.system.ErrnoException +import android.system.Os +import android.system.OsConstants.AF_UNIX +import android.system.OsConstants.SOCK_NONBLOCK +import android.system.OsConstants.SOCK_STREAM +import android.util.LocalLog +import androidx.test.filters.SmallTest +import com.android.net.module.util.HexDump +import com.android.net.module.util.InterfaceParams +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.waitForIdle +import java.io.FileDescriptor +import java.io.InterruptedIOException +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit +import kotlin.test.assertEquals +import libcore.io.IoUtils +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.doReturn +import org.mockito.MockitoAnnotations + +/** + * Test for ConnectivityPacketTracker. + */ +@SmallTest +@DevSdkIgnoreRunner.MonitorThreadLeak +class ConnectivityPacketTrackerTest { + companion object { + private const val TIMEOUT_MS: Long = 10000 + private const val SLEEP_TIMEOUT_MS: Long = 500 + private const val TEST_MAX_CAPTURE_PKT_SIZE: Int = 100 + private const val TAG = "ConnectivityPacketTrackerTest" + } + + private val loInterfaceParams = InterfaceParams.getByName("lo") + private val ifParams = + InterfaceParams( + "lo", + loInterfaceParams.index, + MacAddress.fromBytes(byteArrayOf(2, 3, 4, 5, 6, 7)), + loInterfaceParams.defaultMtu + ) + private val writeSocket = FileDescriptor() + private val handlerThread by lazy { + HandlerThread("$TAG-handler-thread").apply { start() } + } + private val handler by lazy { Handler(handlerThread.looper) } + @Mock private lateinit var mDependencies: Dependencies + @Mock private lateinit var localLog: LocalLog + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val readSocket = FileDescriptor() + Os.socketpair(AF_UNIX, SOCK_STREAM or SOCK_NONBLOCK, 0, writeSocket, readSocket) + doReturn(readSocket).`when`(mDependencies).createPacketReaderSocket(anyInt()) + doReturn(TEST_MAX_CAPTURE_PKT_SIZE).`when`(mDependencies).maxCapturePktSize + } + + @After + fun tearDown() { + IoUtils.closeQuietly(writeSocket) + handler.waitForIdle(10000) + Mockito.framework().clearInlineMocks() + handlerThread.quitSafely() + handlerThread.join() + } + + @Test + fun testCapturePacket() { + val packetTracker = getConnectivityPacketTracker() + // Using scapy to generate ARP request packet: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // arp = ARP() + // pkt = eth/arp + val arpPkt = """ + 010203040506000102030405080600010800060400015c857e3c74e1c0a8012200000000000000000000 + """.replace("\\s+".toRegex(), "").trim().uppercase() + val arpPktByteArray = HexDump.hexStringToByteArray(arpPkt) + assertEquals(0, getTotalCapturePacketCount(packetTracker)) + assertEquals(0, getMatchedPacketCount(packetTracker, arpPkt)) + + // start capture packet + setCapture(packetTracker, true) + + for (i in 1..5) { + pretendPacketReceive(arpPktByteArray) + Thread.sleep(SLEEP_TIMEOUT_MS) + } + + assertEquals(1, getTotalCapturePacketCount(packetTracker)) + assertEquals(5, getMatchedPacketCount(packetTracker, arpPkt)) + + // stop capture packet + setCapture(packetTracker, false) + assertEquals(0, getTotalCapturePacketCount(packetTracker)) + assertEquals(0, getMatchedPacketCount(packetTracker, arpPkt)) + } + + @Test + fun testMaxCapturePacketSize() { + doReturn(3).`when`(mDependencies).maxCapturePktSize + val packetTracker = getConnectivityPacketTracker(mDependencies) + + // Using scapy to generate ARP request packet: + // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") + // arp = ARP() + // pkt = eth/arp + val arpPkt = """ + 010203040506000102030405080600010800060400015c857e3c74e1c0a8012200000000000000000000 + """.replace("\\s+".toRegex(), "").trim().uppercase() + val arpPktByteArray = HexDump.hexStringToByteArray(arpPkt) + // start capture packet + setCapture(packetTracker, true) + val pktCnt = 5 + val pktList = ArrayList<String>() + for (i in 0..<pktCnt) { + // modify the original packet's last byte + val modPkt = arpPktByteArray.copyOf() + modPkt[modPkt.size - 1] = i.toByte() + pretendPacketReceive(modPkt) + pktList.add(HexDump.toHexString(modPkt)) + Thread.sleep(SLEEP_TIMEOUT_MS) + } + + // The old packets are evicted due to LruCache size + pktList.take(2).forEach { + assertEquals(0, getMatchedPacketCount(packetTracker, it)) + } + + pktList.drop(2).forEach { + assertEquals(1, getMatchedPacketCount(packetTracker, it)) + } + + assertEquals(mDependencies.maxCapturePktSize, getTotalCapturePacketCount(packetTracker)) + } + + @Throws(InterruptedIOException::class, ErrnoException::class) + private fun pretendPacketReceive(packet: ByteArray) { + Os.write(writeSocket, packet, 0, packet.size) + } + + private fun getConnectivityPacketTracker( + dependencies: Dependencies = mDependencies + ): ConnectivityPacketTracker { + val result = CompletableFuture<ConnectivityPacketTracker>() + handler.post { + try { + val tracker = ConnectivityPacketTracker(handler, ifParams, localLog, dependencies) + tracker.start(TAG) + result.complete(tracker) + } catch (e: Exception) { + result.completeExceptionally(e) + } + } + + return result.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + } + + private fun setCapture( + packetTracker: ConnectivityPacketTracker, + isCapturing: Boolean + ) { + val result = CompletableFuture<Unit>() + handler.post { + try { + packetTracker.setCapture(isCapturing) + result.complete(Unit) + } catch (e: Exception) { + result.completeExceptionally(e) + } + } + + result.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + } + + private fun getMatchedPacketCount( + packetTracker: ConnectivityPacketTracker, + packet: String + ): Int { + val result = CompletableFuture<Int>() + handler.post { + try { + result.complete(packetTracker.getMatchedPacketCount(packet)) + } catch (e: Exception) { + result.completeExceptionally(e) + } + } + + return result.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + } + + private fun getTotalCapturePacketCount( + packetTracker: ConnectivityPacketTracker + ): Int { + val result = CompletableFuture<Int>() + handler.post { + try { + val totalCnt = packetTracker.totalCapturePacketCount + result.complete(totalCnt) + } catch (e: Exception) { + result.completeExceptionally(e) + } + } + + return result.get(TIMEOUT_MS, TimeUnit.MILLISECONDS) + } +} \ No newline at end of file
diff --git a/tests/unit/src/android/net/ip/IpClientTest.java b/tests/unit/src/android/net/ip/IpClientTest.java index 71f7ebf..0df8a31 100644 --- a/tests/unit/src/android/net/ip/IpClientTest.java +++ b/tests/unit/src/android/net/ip/IpClientTest.java
@@ -850,10 +850,10 @@ ApfConfiguration.class); if (isApfSupported) { verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter( - any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); + any(), any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); } else { verify(mDependencies, never()).maybeCreateApfFilter( - any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); + any(), any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); } return isApfSupported ? configCaptor.getValue() : null; @@ -922,7 +922,7 @@ final ArgumentCaptor<ApfConfiguration> configCaptor = ArgumentCaptor.forClass( ApfConfiguration.class); verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter( - any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); + any(), any(), configCaptor.capture(), any(), any(), any(), anyBoolean()); final ApfConfiguration actual = configCaptor.getValue(); assertNotNull(actual); assertEquals(SdkLevel.isAtLeastS() ? 4 : 3, actual.apfVersionSupported); @@ -957,7 +957,7 @@ ipc.updateApfCapabilities(newApfCapabilities); HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS); verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any(), any(), - anyBoolean()); + any(), anyBoolean()); verifyShutdown(ipc); } @@ -973,15 +973,15 @@ ipc.updateApfCapabilities(null /* apfCapabilities */); HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS); verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any(), any(), - anyBoolean()); + any(), anyBoolean()); verifyShutdown(ipc); } @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public void testVendorNdOffloadDisabledWhenApfV6Supported() throws Exception { - when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), anyBoolean())) - .thenReturn(mApfFilter); + when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), any(), + anyBoolean())).thenReturn(mApfFilter); when(mApfFilter.supportNdOffload()).thenReturn(true); final IpClient ipc = makeIpClient(TEST_IFNAME); ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() @@ -1006,8 +1006,8 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public void testVendorNdOffloadEnabledWhenApfV6NotSupported() throws Exception { - when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), anyBoolean())) - .thenReturn(mApfFilter); + when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), any(), + anyBoolean())).thenReturn(mApfFilter); when(mApfFilter.supportNdOffload()).thenReturn(false); final IpClient ipc = makeIpClient(TEST_IFNAME); ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() @@ -1030,8 +1030,8 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public void testVendorNdOffloadDisabledWhenApfCapabilitiesUpdated() throws Exception { - when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), anyBoolean())) - .thenReturn(mApfFilter); + when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), any(), + anyBoolean())).thenReturn(mApfFilter); when(mApfFilter.supportNdOffload()).thenReturn(true); final IpClient ipc = makeIpClient(TEST_IFNAME); ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() @@ -1053,8 +1053,8 @@ @Test public void testLinkPropertiesUpdate_callSetLinkPropertiesOnApfFilter() throws Exception { - when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), anyBoolean())) - .thenReturn(mApfFilter); + when(mDependencies.maybeCreateApfFilter(any(), any(), any(), any(), any(), any(), + anyBoolean())).thenReturn(mApfFilter); final IpClient ipc = makeIpClient(TEST_IFNAME); verifyApfFilterCreatedOnStart(ipc, true /* isApfSupported */); onInterfaceAddressUpdated(
diff --git a/tests/unit/src/android/net/shared/PrivateDnsConfigTest.java b/tests/unit/src/android/net/shared/PrivateDnsConfigTest.java index 94f04d5..2320470 100644 --- a/tests/unit/src/android/net/shared/PrivateDnsConfigTest.java +++ b/tests/unit/src/android/net/shared/PrivateDnsConfigTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import android.net.PrivateDnsConfigParcel; @@ -55,6 +57,7 @@ assertEquals(a.mode, b.mode); assertEquals(a.hostname, b.hostname); assertArrayEquals(a.ips, b.ips); + assertEquals(a.ddrEnabled, b.ddrEnabled); assertEquals(a.dohName, b.dohName); assertArrayEquals(a.dohIps, b.dohIps); assertEquals(a.dohPath, b.dohPath); @@ -65,6 +68,7 @@ assertEquals(parcel.privateDnsMode, cfg.mode); assertEquals(parcel.hostname, cfg.hostname); assertArrayEquals(parcel.ips, toStringArray(cfg.ips)); + assertEquals(parcel.ddrEnabled, cfg.ddrEnabled); assertEquals(parcel.dohName, cfg.dohName); assertEquals(parcel.dohPath, cfg.dohPath); assertEquals(parcel.dohPort, cfg.dohPort); @@ -102,19 +106,23 @@ // String dohName, InetAddress[] dohIps, String dohPath, int dohPort) for (int mode : new int[] { OFF_MODE, OPPORTUNISTIC_MODE, STRICT_MODE }) { testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, null, null, - null, null, null, -1)); + false, null, null, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", null, - null, null, null, -1)); + false, null, null, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, - null, null, null, -1)); + false, null, null, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, - "doh.com", null, null, -1)); + true, null, null, null, -1)); + testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", null, + true, null, null, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, - "doh.com", TEST_ADDRS, null, -1)); + true, "doh.com", null, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, - "doh.com", TEST_ADDRS, "dohpath=/some-path{?dns}", -1)); + true, "doh.com", TEST_ADDRS, null, -1)); testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, - "doh.com", TEST_ADDRS, "dohpath=/some-path{?dns}", 443)); + true, "doh.com", TEST_ADDRS, "dohpath=/some-path{?dns}", -1)); + testPrivateDnsConfigConversion(new PrivateDnsConfig(mode, "dns.com", TEST_ADDRS, + true, "doh.com", TEST_ADDRS, "dohpath=/some-path{?dns}", 443)); } } @@ -123,11 +131,30 @@ final InetAddress ip = InetAddress.parseNumericAddress("1.2.3.4"); final InetAddress[] ipArray = new InetAddress[] { ip }; final PrivateDnsConfig cfg = new PrivateDnsConfig(OPPORTUNISTIC_MODE, null /* hostname */, - ipArray /* ips */, null /* dohName */, ipArray /* dohIps */, null /* dohPath */, - -1 /* dohPort */); + ipArray /* ips */, false /* ddrEnabled */, null /* dohName */, ipArray /* dohIps */, + null /* dohPath */, -1 /* dohPort */); ipArray[0] = InetAddress.parseNumericAddress("2001:db8::2"); assertArrayEquals(new InetAddress[] { ip }, cfg.ips); assertArrayEquals(new InetAddress[] { ip }, cfg.dohIps); } + + @Test + public void testSettingsComparison() { + final PrivateDnsConfig off = new PrivateDnsConfig(false); + final PrivateDnsConfig opportunistic = new PrivateDnsConfig(true); + final PrivateDnsConfig strict = new PrivateDnsConfig("dns.com", null); + + assertFalse(opportunistic.areSettingsSameAs(off)); + assertFalse(opportunistic.areSettingsSameAs(strict)); + assertTrue(opportunistic.areSettingsSameAs(new PrivateDnsConfig( + OPPORTUNISTIC_MODE, null, TEST_ADDRS, false, null, null, null, -1))); + + assertFalse(strict.areSettingsSameAs(off)); + assertFalse(strict.areSettingsSameAs(opportunistic)); + assertTrue(strict.areSettingsSameAs(new PrivateDnsConfig( + STRICT_MODE, "dns.com", TEST_ADDRS, false, null, null, null, -1))); + assertFalse(strict.areSettingsSameAs(new PrivateDnsConfig( + STRICT_MODE, "foo.com", TEST_ADDRS, false, null, null, null, -1))); + } }
diff --git a/tests/unit/src/android/net/testutils/NetworkStatsUtilsTest.kt b/tests/unit/src/android/net/testutils/NetworkStatsUtilsTest.kt deleted file mode 100644 index 2e76c52..0000000 --- a/tests/unit/src/android/net/testutils/NetworkStatsUtilsTest.kt +++ /dev/null
@@ -1,70 +0,0 @@ -/* - * Copyright (C) 2020 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.testutils - -import android.net.NetworkStats -import android.net.NetworkStats.DEFAULT_NETWORK_NO -import android.net.NetworkStats.METERED_NO -import android.net.NetworkStats.ROAMING_NO -import android.net.NetworkStats.SET_DEFAULT -import android.net.NetworkStats.TAG_NONE -import android.os.Build -import com.android.testutils.DevSdkIgnoreRule -import com.android.testutils.orderInsensitiveEquals -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -private const val TEST_IFACE = "test0" -private const val TEST_IFACE2 = "test2" -private const val TEST_START = 1194220800000L - -@RunWith(JUnit4::class) -class NetworkStatsUtilsTest { - // This is a unit test for a test utility that uses R APIs - @Rule @JvmField - val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) - - @Test - fun testOrderInsensitiveEquals() { - val testEntry = arrayOf( - NetworkStats.Entry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L), - NetworkStats.Entry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)) - - // Verify equals of empty stats regardless of initial capacity. - val red = NetworkStats(TEST_START, 0) - val blue = NetworkStats(TEST_START, 1) - assertTrue(orderInsensitiveEquals(red, blue)) - assertTrue(orderInsensitiveEquals(blue, red)) - - // Verify not equal. - red.combineValues(testEntry[1]) - blue.combineValues(testEntry[0]).combineValues(testEntry[1]) - assertFalse(orderInsensitiveEquals(red, blue)) - assertFalse(orderInsensitiveEquals(blue, red)) - - // Verify equals even if the order of entries are not the same. - red.combineValues(testEntry[0]) - assertTrue(orderInsensitiveEquals(red, blue)) - assertTrue(orderInsensitiveEquals(blue, red)) - } -} \ No newline at end of file
diff --git a/tests/unit/src/com/android/networkstack/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/unit/src/com/android/networkstack/ipmemorystore/IpMemoryStoreServiceTest.java index d192425..7d11f80 100644 --- a/tests/unit/src/com/android/networkstack/ipmemorystore/IpMemoryStoreServiceTest.java +++ b/tests/unit/src/com/android/networkstack/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -16,6 +16,7 @@ package com.android.networkstack.ipmemorystore; +import static com.android.networkstack.ipmemorystore.IpMemoryStoreDatabase.DbHelper.SCHEMA_VERSION; import static com.android.networkstack.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance; import static org.junit.Assert.assertEquals; @@ -29,6 +30,8 @@ import android.app.job.JobScheduler; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; import android.net.ipmemorystore.Blob; import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; @@ -99,8 +102,9 @@ private static final long UNIX_TIME_MS_2100_01_01 = 4102412400000L; private static final int MTU_NULL = -1; private static final String[] FAKE_KEYS; - private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12, - -128, 0, 89, 112, 91, -34 }; + private static final byte[] TEST_BLOB_DATA = new byte[]{-3, 6, 8, -9, 12, + -128, 0, 89, 112, 91, -34}; + static { FAKE_KEYS = new String[FAKE_KEY_COUNT]; for (int i = 0; i < FAKE_KEYS.length; ++i) { @@ -235,6 +239,7 @@ private interface OnBlobRetrievedListener { void onBlobRetrieved(Status status, String l2Key, String name, byte[] data); } + private IOnBlobRetrievedListener onBlobRetrieved(final OnBlobRetrievedListener functor) { return new IOnBlobRetrievedListener() { @Override @@ -262,9 +267,10 @@ } /** Helper method to make an IOnNetworkAttributesRetrievedListener */ - private interface OnNetworkAttributesRetrievedListener { + private interface OnNetworkAttributesRetrievedListener { void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr); } + private IOnNetworkAttributesRetrievedListener onNetworkAttributesRetrieved( final OnNetworkAttributesRetrievedListener functor) { return new IOnNetworkAttributesRetrievedListener() { @@ -297,6 +303,7 @@ private interface OnSameL3NetworkResponseListener { void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer); } + private IOnSameL3NetworkResponseListener onSameResponse( final OnSameL3NetworkResponseListener functor) { return new IOnSameL3NetworkResponseListener() { @@ -329,6 +336,7 @@ private interface OnL2KeyResponseListener { void onL2KeyResponse(Status status, String key); } + private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) { return new IOnL2KeyResponseListener() { @Override @@ -376,6 +384,7 @@ private NetworkAttributes storeAttributes(final String l2Key, final NetworkAttributes na) { return storeAttributes("Did not complete storing attributes", l2Key, na); } + private NetworkAttributes storeAttributes(final String timeoutMessage, final String l2Key, final NetworkAttributes na) { doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(), @@ -390,6 +399,7 @@ private void storeBlobOrFail(final String l2Key, final Blob b, final byte[] data) { storeBlobOrFail("Did not complete storing private data", l2Key, b, data); } + private void storeBlobOrFail(final String timeoutMessage, final String l2Key, final Blob b, final byte[] data) { b.data = data; @@ -409,8 +419,7 @@ * 2. Comment out "mDbFile.delete()" in tearDown() method. * 3. Run "atest IpMemoryStoreServiceTest#testGenerateDB". * 4. Run "adb root; adb pull /data/data/com.android.server.networkstack.tests/files/test.db - * $YOUR_CODE_BASE/package/module/NetworkStack/tests/unit/res/raw/test.db". - * + * $YOUR_CODE_BASE/package/module/NetworkStack/tests/unit/res/raw/test.db". */ private void generateFakeData() { final int fakeDataCount = 1000; @@ -473,7 +482,7 @@ final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder(); na.setDnsAddresses(Arrays.asList( - new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")})); + new InetAddress[]{Inet6Address.getByName("0A1C:2E40:480A::1CA6")})); final NetworkAttributes attributes2 = na2.build(); storeAttributes("Did not complete storing attributes 2", l2Key, attributes2); @@ -587,13 +596,13 @@ stored.add(storeAttributes(FAKE_KEYS[0], na.build())); na.setDnsAddresses(Arrays.asList( - new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")})); + new InetAddress[]{Inet6Address.getByName("8D56:9AF1::08EE:20F1")})); na.setMtu(208); stored.add(storeAttributes(FAKE_KEYS[1], na.build())); na.setMtu(null); na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4")); na.setDnsAddresses(Arrays.asList( - new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")})); + new InetAddress[]{Inet6Address.getByName("0A1C:2E40:480A::1CA6")})); na.setCluster("cluster1"); stored.add(storeAttributes(FAKE_KEYS[2], na.build())); na.setMtu(219); @@ -922,13 +931,13 @@ private final List<Pair<String, byte[]>> mByteArrayTests = List.of( new Pair<>("null", null), - new Pair<>("[]", new byte[] {}), + new Pair<>("[]", new byte[]{}), new Pair<>("[0102030405060708090A0B0C]", - new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }), - new Pair<>("[0F1080FF]", new byte[] { 15, 16, -128, -1 }), + new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}), + new Pair<>("[0F1080FF]", new byte[]{15, 16, -128, -1}), new Pair<>("[0102030405060708090A0B0C0D0E0F10...15161718191A1B1C]", - new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }) + new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}) ); @Test @@ -976,4 +985,29 @@ //db is null, the db size could not over the threshold. assertFalse(ipMemoryStoreService.isDbSizeOverThreshold()); } + + private void doTestDowngradeAndUpgrade(int downgradeVersion) { + SQLiteOpenHelper dbHelper = new IpMemoryStoreDatabase.DbHelper( + mMockContext, downgradeVersion); + SQLiteDatabase db = dbHelper.getWritableDatabase(); + assertEquals(downgradeVersion, db.getVersion()); + db.close(); + + dbHelper = new IpMemoryStoreDatabase.DbHelper(mMockContext, SCHEMA_VERSION); + db = dbHelper.getWritableDatabase(); + assertEquals(SCHEMA_VERSION, db.getVersion()); + db.close(); + } + + @Test + public void testDowngradeClearsTablesAndriggers() { + final String l2Key = FAKE_KEYS[0]; + final Blob b = new Blob(); + storeBlobOrFail(l2Key, b, TEST_BLOB_DATA); + mService.shutdown(); + + for (int version = SCHEMA_VERSION - 1; version >= 1; version--) { + doTestDowngradeAndUpgrade(version); + } + } }
diff --git a/tests/unit/src/com/android/server/connectivity/DdrTrackerTest.java b/tests/unit/src/com/android/server/connectivity/DdrTrackerTest.java index dcc4291..77630c7 100644 --- a/tests/unit/src/com/android/server/connectivity/DdrTrackerTest.java +++ b/tests/unit/src/com/android/server/connectivity/DdrTrackerTest.java
@@ -20,20 +20,28 @@ import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.annotation.NonNull; +import android.net.DnsResolver; +import android.net.LinkProperties; +import android.net.Network; import android.net.shared.PrivateDnsConfig; +import com.android.net.module.util.SharedLog; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.InetAddress; +import java.util.concurrent.Executor; @RunWith(JUnit4.class) public final class DdrTrackerTest { @@ -42,11 +50,22 @@ private static final int STRICT_MODE = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; private DdrTracker mDdrTracker; + private @Mock DnsResolver mDnsResolver; + private @Mock Network mCleartextDnsNetwork; + private @Mock TestCallback mCallback; + private @Mock Executor mExecutor; + private @Mock SharedLog mValidationLogger; + + // TODO(b/240259333): Fake DNS responses on mDnsResolver to test startSvcbLookup. + private static class TestCallback implements DdrTracker.Callback { + @Override + public void onSvcbLookupComplete(@NonNull PrivateDnsConfig result) {} + } private static class PrivateDnsConfigBuilder { private int mMode = OFF_MODE; private String mHostname = null; - private final InetAddress[] mIps = null; + private InetAddress[] mIps = null; private final String mDohName = null; private final InetAddress[] mDohIps = null; private final String mDohPath = null; @@ -60,18 +79,24 @@ mHostname = value; return this; } + PrivateDnsConfigBuilder setIps(InetAddress[] value) { + mIps = value; + return this; + } PrivateDnsConfig build() { - return new PrivateDnsConfig(mMode, mHostname, mIps, mDohName, mDohIps, mDohPath, - mDohPort); + return new PrivateDnsConfig(mMode, mHostname, mIps, + false /* ddrEnabled */, mDohName, mDohIps, mDohPath, mDohPort); } } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mDdrTracker = new DdrTracker(); + mDdrTracker = new DdrTracker(mCleartextDnsNetwork, mDnsResolver, mExecutor, mCallback, + mValidationLogger); } + // TODO: check that if DeviceConfigUtils#isFeatureSupported returns false, DDR is disabled. private void testNotifyPrivateDnsSettingsChangedHelper(int mode, @NonNull String dnsProvider) throws Exception { final PrivateDnsConfig cfg = @@ -87,7 +112,6 @@ public void testNotifyPrivateDnsSettingsChanged() throws Exception { // Tests the initial private DNS setting in DdrTracker. assertEquals(OFF_MODE, mDdrTracker.getPrivateDnsMode()); - assertEquals("", mDdrTracker.getStrictModeHostname()); assertFalse(mDdrTracker.notifyPrivateDnsSettingsChanged(new PrivateDnsConfigBuilder() .setMode(OFF_MODE).build())); @@ -97,4 +121,59 @@ testNotifyPrivateDnsSettingsChangedHelper(STRICT_MODE, "example2.com"); testNotifyPrivateDnsSettingsChangedHelper(OFF_MODE, ""); } + + private void testNotifyLinkPropertiesChangedHelper(InetAddress[] ips) { + final LinkProperties lp = new LinkProperties(); + for (InetAddress ip : ips) { + assertTrue(lp.addDnsServer(ip)); + } + assertTrue(mDdrTracker.notifyLinkPropertiesChanged(lp)); + assertArrayEquals(ips, mDdrTracker.getDnsServers().toArray()); + assertFalse(mDdrTracker.notifyLinkPropertiesChanged(lp)); + } + + @Test + public void testNotifyLinkPropertiesChanged() throws Exception { + final InetAddress ip1 = InetAddress.parseNumericAddress("1.2.3.4"); + final InetAddress ip2 = InetAddress.parseNumericAddress("2001:db8::1"); + + // Tests the initial value in DdrTracker. + assertTrue(mDdrTracker.getDnsServers().isEmpty()); + + testNotifyLinkPropertiesChangedHelper(new InetAddress[] {ip1}); + testNotifyLinkPropertiesChangedHelper(new InetAddress[] {ip1, ip2}); + testNotifyLinkPropertiesChangedHelper(new InetAddress[] {ip2, ip1}); + } + + private void assertPrivateDnsConfigEquals(PrivateDnsConfig a, PrivateDnsConfig b) { + assertEquals(a.mode, b.mode); + assertEquals(a.hostname, b.hostname); + assertArrayEquals(a.ips, b.ips); + assertEquals(a.dohName, b.dohName); + assertArrayEquals(a.dohIps, b.dohIps); + assertEquals(a.dohPath, b.dohPath); + assertEquals(a.dohPort, b.dohPort); + } + + @Test + public void testSetStrictModeHostnameResolutionResult() throws Exception { + final String dnsProvider = "example1.com"; + final InetAddress[] ips = new InetAddress[] { + InetAddress.parseNumericAddress("1.2.3.4"), + InetAddress.parseNumericAddress("2001:db8::1"), + }; + final PrivateDnsConfigBuilder builder = + new PrivateDnsConfigBuilder().setMode(STRICT_MODE).setHostname(dnsProvider); + + assertTrue(mDdrTracker.notifyPrivateDnsSettingsChanged(builder.build())); + assertPrivateDnsConfigEquals(builder.build(), mDdrTracker.getResultForReporting()); + + mDdrTracker.setStrictModeHostnameResolutionResult(ips); + assertPrivateDnsConfigEquals(builder.setIps(ips).build(), + mDdrTracker.getResultForReporting()); + + mDdrTracker.resetStrictModeHostnameResolutionResult(); + assertPrivateDnsConfigEquals(builder.setIps(new InetAddress[0]).build(), + mDdrTracker.getResultForReporting()); + } }
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java index d5d1c90..9a86d9f 100644 --- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -104,7 +104,6 @@ import static java.lang.System.currentTimeMillis; import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; import android.annotation.NonNull; import android.annotation.SuppressLint; @@ -121,7 +120,6 @@ import android.net.DnsResolver; import android.net.INetd; import android.net.INetworkMonitorCallbacks; -import android.net.InetAddresses; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgentConfig; @@ -388,11 +386,11 @@ class DnsEntry { final String mHostname; final int mType; - final AddressSupplier mAddressesSupplier; - DnsEntry(String host, int type, AddressSupplier addr) { + final AnswerSupplier mAnswerSupplier; + DnsEntry(String host, int type, AnswerSupplier answerSupplier) { mHostname = host; mType = type; - mAddressesSupplier = addr; + mAnswerSupplier = answerSupplier; } // Full match or partial match that target host contains the entry hostname to support // random private dns probe hostname. @@ -400,22 +398,22 @@ return hostname.endsWith(mHostname) && type == mType; } } - interface AddressSupplier { - List<InetAddress> get() throws DnsResolver.DnsException; + interface AnswerSupplier { + List<String> get() throws DnsResolver.DnsException; } - class InstantAddressSupplier implements AddressSupplier { - private final List<InetAddress> mAddresses; - InstantAddressSupplier(List<InetAddress> addresses) { - mAddresses = addresses; + class InstantAnswerSupplier implements AnswerSupplier { + private final List<String> mAnswers; + InstantAnswerSupplier(List<String> answers) { + mAnswers = answers; } @Override - public List<InetAddress> get() { - return mAddresses; + public List<String> get() { + return mAnswers; } } - private final ArrayList<DnsEntry> mAnswers = new ArrayList<DnsEntry>(); + private final ArrayList<DnsEntry> mAnswers = new ArrayList<>(); private boolean mNonBypassPrivateDnsWorking = true; /** Whether DNS queries on mNonBypassPrivateDnsWorking should succeed. */ @@ -431,29 +429,29 @@ } /** Returns the answer for a given name and type on the given mock network. */ - private CompletableFuture<List<InetAddress>> getAnswer(Network mockNetwork, String hostname, + private CompletableFuture<List<String>> getAnswer(Network mockNetwork, String hostname, int type) { if (mockNetwork == mNetwork && !mNonBypassPrivateDnsWorking) { return CompletableFuture.completedFuture(null); } - final AddressSupplier answerSupplier; + final AnswerSupplier answerSupplier; synchronized (mAnswers) { answerSupplier = mAnswers.stream() .filter(e -> e.matches(hostname, type)) - .map(answer -> answer.mAddressesSupplier).findFirst().orElse(null); + .map(answer -> answer.mAnswerSupplier).findFirst().orElse(null); } if (answerSupplier == null) { return CompletableFuture.completedFuture(null); } - if (answerSupplier instanceof InstantAddressSupplier) { + if (answerSupplier instanceof InstantAnswerSupplier) { // Save latency waiting for a query thread if the answer is hardcoded. return CompletableFuture.completedFuture( - ((InstantAddressSupplier) answerSupplier).get()); + ((InstantAnswerSupplier) answerSupplier).get()); } - final CompletableFuture<List<InetAddress>> answerFuture = new CompletableFuture<>(); + final CompletableFuture<List<String>> answerFuture = new CompletableFuture<>(); new Thread(() -> { try { answerFuture.complete(answerSupplier.get()); @@ -466,10 +464,11 @@ /** Sets the answer for a given name and type. */ private void setAnswer(String hostname, String[] answer, int type) { - setAnswer(hostname, new InstantAddressSupplier(generateAnswer(answer)), type); + setAnswer(hostname, new InstantAnswerSupplier( + (answer == null) ? null : Arrays.asList(answer)), type); } - private void setAnswer(String hostname, AddressSupplier answerSupplier, int type) { + private void setAnswer(String hostname, AnswerSupplier answerSupplier, int type) { DnsEntry record = new DnsEntry(hostname, type, answerSupplier); synchronized (mAnswers) { // Remove the existing one. @@ -479,9 +478,8 @@ } } - private List<InetAddress> generateAnswer(String[] answer) { - if (answer == null) return new ArrayList<>(); - return Arrays.stream(answer).map(InetAddresses::parseNumericAddress).collect(toList()); + private byte[] makeSvcbResponse(String hostname, List<String> answer) { + throw new UnsupportedOperationException("Not supported, update this fake"); } /** Simulates a getAllByName call for the specified name on the specified mock network. */ @@ -489,8 +487,8 @@ throws UnknownHostException { final List<InetAddress> answer; try { - answer = queryAllTypes(mockNetwork, hostname).get( - HANDLER_TIMEOUT_MS, TimeUnit.MILLISECONDS); + answer = stringsToInetAddresses(queryAllTypes(mockNetwork, hostname).get( + HANDLER_TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (ExecutionException | InterruptedException | TimeoutException e) { throw new AssertionError("No mock DNS reply within timeout", e); } @@ -501,22 +499,22 @@ } // Regardless of the type, depends on what the responses contained in the network. - private CompletableFuture<List<InetAddress>> queryAllTypes( + private CompletableFuture<List<String>> queryAllTypes( Network mockNetwork, String hostname) { if (mockNetwork == mNetwork && !mNonBypassPrivateDnsWorking) { return CompletableFuture.completedFuture(null); } - final CompletableFuture<List<InetAddress>> aFuture = + final CompletableFuture<List<String>> aFuture = getAnswer(mockNetwork, hostname, TYPE_A) .exceptionally(e -> Collections.emptyList()); - final CompletableFuture<List<InetAddress>> aaaaFuture = + final CompletableFuture<List<String>> aaaaFuture = getAnswer(mockNetwork, hostname, TYPE_AAAA) .exceptionally(e -> Collections.emptyList()); - final CompletableFuture<List<InetAddress>> combinedFuture = new CompletableFuture<>(); + final CompletableFuture<List<String>> combinedFuture = new CompletableFuture<>(); aFuture.thenAcceptBoth(aaaaFuture, (res1, res2) -> { - final List<InetAddress> answer = new ArrayList<>(); + final List<String> answer = new ArrayList<>(); if (res1 != null) answer.addAll(res1); if (res2 != null) answer.addAll(res2); combinedFuture.complete(answer); @@ -544,15 +542,24 @@ }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any()); } + private List<InetAddress> stringsToInetAddresses(List<String> addrs) { + if (addrs == null) return null; + final List<InetAddress> out = new ArrayList<>(); + for (String addr : addrs) { + out.add(parseNumericAddress(addr)); + } + return out; + } + // Mocking queries on DnsResolver#query. private Answer mockQuery(InvocationOnMock invocation, int posNetwork, int posHostname, int posExecutor, int posCallback, int posType) { String hostname = (String) invocation.getArgument(posHostname); Executor executor = (Executor) invocation.getArgument(posExecutor); - DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(posCallback); Network network = invocation.getArgument(posNetwork); + DnsResolver.Callback callback = invocation.getArgument(posCallback); - final CompletableFuture<List<InetAddress>> answerFuture = posType != -1 + final CompletableFuture<List<String>> answerFuture = (posType != -1) ? getAnswer(network, hostname, invocation.getArgument(posType)) : queryAllTypes(network, hostname); @@ -566,7 +573,18 @@ return; } if (answer != null && answer.size() > 0) { - callback.onAnswer(answer, 0); + final int qtype = (posType != -1) + ? invocation.getArgument(posType) : TYPE_AAAA; + switch (qtype) { + // Assume A and AAAA queries use the List<InetAddress> callback. + case TYPE_A: + case TYPE_AAAA: + callback.onAnswer(stringsToInetAddresses(answer), 0); + break; + default: + throw new UnsupportedOperationException( + "Unsupported qtype: " + qtype + ", update this fake"); + } } })); }); @@ -2561,7 +2579,7 @@ final ConditionVariable v4Queried = new ConditionVariable(); mFakeDns.setAnswer("dns.google", () -> { v4Queried.open(); - return List.of(parseNumericAddress("192.0.2.123")); + return List.of("192.0.2.123"); }, TYPE_A); mFakeDns.setAnswer("dns.google", () -> { // Make sure the v6 query processing is a bit slower than the v6 one. The small delay @@ -2570,7 +2588,7 @@ // not, the test should pass. v4Queried.block(HANDLER_TIMEOUT_MS); SystemClock.sleep(10L); - return List.of(parseNumericAddress("2001:db8::1"), parseNumericAddress("2001:db8::2")); + return List.of("2001:db8::1", "2001:db8::2"); }, TYPE_AAAA); notifyNetworkConnected(wnm, CELL_NOT_METERED_CAPABILITIES); @@ -2601,12 +2619,12 @@ mFakeDns.setAnswer("v1.google", () -> { queriedLatch.countDown(); blockReplies.block(HANDLER_TIMEOUT_MS); - return List.of(parseNumericAddress("192.0.2.123")); + return List.of("192.0.2.123"); }, TYPE_A); mFakeDns.setAnswer("v1.google", () -> { queriedLatch.countDown(); blockReplies.block(HANDLER_TIMEOUT_MS); - return List.of(parseNumericAddress("2001:db8::1")); + return List.of("2001:db8::1"); }, TYPE_AAAA); notifyNetworkConnected(wnm, CELL_NOT_METERED_CAPABILITIES); @@ -2649,12 +2667,12 @@ mFakeDns.setAnswer("v1.google", () -> { queriedLatch.countDown(); blockReplies.block(HANDLER_TIMEOUT_MS); - return List.of(parseNumericAddress("192.0.2.123")); + return List.of("192.0.2.123"); }, TYPE_A); mFakeDns.setAnswer("v1.google", () -> { queriedLatch.countDown(); blockReplies.block(HANDLER_TIMEOUT_MS); - return List.of(parseNumericAddress("2001:db8::1")); + return List.of("2001:db8::1"); }, TYPE_AAAA); notifyNetworkConnected(wnm, CELL_NOT_METERED_CAPABILITIES); @@ -3262,11 +3280,11 @@ mFakeDns.setAnswer("www.google.com", () -> { // Make sure the DNS probes take at least 1ms SystemClock.sleep(1); - return List.of(parseNumericAddress("2001:db8::443")); + return List.of("2001:db8::443"); }, TYPE_AAAA); mFakeDns.setAnswer(PRIVATE_DNS_PROBE_HOST_SUFFIX, () -> { SystemClock.sleep(1); - return List.of(parseNumericAddress("2001:db8::444")); + return List.of("2001:db8::444"); }, TYPE_AAAA); setStatus(mHttpsConnection, 204); setStatus(mHttpConnection, 204);