summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp11
-rwxr-xr-xapi/current.txt8
-rw-r--r--api/system-current.txt6
-rw-r--r--cmds/statsd/src/atoms.proto26
-rw-r--r--config/hiddenapi-greylist.txt3
-rw-r--r--core/java/android/net/IpPrefixParcelable.aidl22
-rw-r--r--core/java/android/net/LinkAddressParcelable.aidl24
-rw-r--r--core/java/android/net/LinkProperties.java1
-rw-r--r--core/java/android/net/LinkPropertiesParcelable.aidl39
-rw-r--r--core/java/android/net/ProxyInfoParcelable.aidl24
-rw-r--r--core/java/android/net/RouteInfoParcelable.aidl26
-rw-r--r--core/java/android/net/ipmemorystore/NetworkAttributes.java49
-rw-r--r--core/java/android/net/ipmemorystore/SameL3NetworkResponse.java15
-rw-r--r--core/java/android/net/ipmemorystore/Status.java12
-rw-r--r--core/java/android/net/ipmemorystore/Utils.java44
-rw-r--r--core/java/android/os/BugreportManager.java13
-rw-r--r--core/java/android/os/INetworkManagementService.aidl10
-rw-r--r--core/java/android/view/LayoutInflater.java261
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java40
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImplNative.java301
-rw-r--r--core/jni/android_app_NativeActivity.cpp5
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto89
-rw-r--r--data/etc/Android.bp4
-rw-r--r--data/etc/platform.xml6
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java3
-rw-r--r--packages/services/PacProcessor/Android.mk2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java2
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java45
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java13
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java14
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java1
-rw-r--r--services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java143
-rw-r--r--services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java79
-rw-r--r--services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java307
-rw-r--r--services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java222
-rw-r--r--services/net/java/android/net/shared/ParcelableUtil.java63
-rw-r--r--telecomm/java/android/telecom/CallRedirectionService.java76
-rw-r--r--telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl3
-rw-r--r--telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl2
-rw-r--r--telephony/java/android/telephony/AvailableNetworkInfo.java1
-rw-r--r--telephony/java/android/telephony/CellConfigLte.java5
-rw-r--r--telephony/java/android/telephony/CellInfo.java22
-rw-r--r--telephony/java/android/telephony/CellInfoCdma.java9
-rw-r--r--telephony/java/android/telephony/CellInfoGsm.java8
-rw-r--r--telephony/java/android/telephony/CellInfoLte.java9
-rw-r--r--telephony/java/android/telephony/CellInfoTdscdma.java8
-rw-r--r--telephony/java/android/telephony/CellInfoWcdma.java8
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java2
-rw-r--r--telephony/java/android/telephony/emergency/EmergencyNumber.java140
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java75
-rw-r--r--test-base/api/current.txt3
-rw-r--r--test-base/src/android/test/RepetitiveTest.java6
-rw-r--r--test-legacy/Android.bp2
-rw-r--r--test-mock/Android.bp16
-rw-r--r--tests/net/java/android/net/LinkPropertiesTest.java27
-rw-r--r--tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java193
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java4
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java6
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java30
-rw-r--r--tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java6
-rw-r--r--tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java149
61 files changed, 2154 insertions, 589 deletions
diff --git a/Android.bp b/Android.bp
index ab2bd9d98a6b..580df85f7dad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -704,7 +704,6 @@ java_defaults {
required: [
// TODO: remove gps_debug when the build system propagates "required" properly.
"gps_debug.conf",
- "libtextclassifier",
// Loaded with System.loadLibrary by android.view.textclassifier
"libmedia2_jni",
],
@@ -830,7 +829,12 @@ aidl_interface {
"core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
+ "core/java/android/net/IpPrefixParcelable.aidl",
+ "core/java/android/net/LinkAddressParcelable.aidl",
+ "core/java/android/net/LinkPropertiesParcelable.aidl",
"core/java/android/net/PrivateDnsConfigParcel.aidl",
+ "core/java/android/net/ProxyInfoParcelable.aidl",
+ "core/java/android/net/RouteInfoParcelable.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
@@ -850,6 +854,10 @@ java_library {
"nist-sip",
"tagsoup",
"rappor",
+ "libtextclassifier-java",
+ ],
+ required: [
+ "libtextclassifier",
],
dxflags: ["--core-library"],
}
@@ -1256,7 +1264,6 @@ stubs_defaults {
"ext",
"framework",
"voip-common",
- "android.test.mock.impl",
],
local_sourcepaths: frameworks_base_subdirs,
installable: false,
diff --git a/api/current.txt b/api/current.txt
index c3b77cb22202..69be5e599a1c 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -41302,10 +41302,10 @@ package android.telecom {
ctor public CallRedirectionService();
method public final void cancelCall();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
method public final boolean onUnbind(android.content.Intent);
method public final void placeCallUnmodified();
- method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
}
@@ -43380,6 +43380,7 @@ package android.telephony.emergency {
method public int compareTo(android.telephony.emergency.EmergencyNumber);
method public int describeContents();
method public java.lang.String getCountryIso();
+ method public int getEmergencyCallRouting();
method public int getEmergencyNumberSourceBitmask();
method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
@@ -43390,6 +43391,9 @@ package android.telephony.emergency {
method public boolean isInEmergencyServiceCategories(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR;
+ field public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1; // 0x1
+ field public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; // 0x2
+ field public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; // 0x0
field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10
field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8
field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index 7daab8669530..9cdc68284b14 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5556,9 +5556,9 @@ package android.telephony {
public class SubscriptionManager {
method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
method public void requestEmbeddedSubscriptionInfoListRefresh();
+ method public void requestEmbeddedSubscriptionInfoListRefresh(int);
method public void setDefaultDataSubId(int);
method public void setDefaultSmsSubId(int);
- method public void requestEmbeddedSubscriptionInfoListRefresh(int);
field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
@@ -6040,6 +6040,7 @@ package android.telephony.ims {
method public android.os.Bundle getCallExtras();
method public int getCallType();
method public static int getCallTypeFromVideoState(int);
+ method public int getEmergencyCallRouting();
method public int getEmergencyServiceCategories();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
method public int getRestrictCause();
@@ -6053,6 +6054,7 @@ package android.telephony.ims {
method public void setCallExtraBoolean(java.lang.String, boolean);
method public void setCallExtraInt(java.lang.String, int);
method public void setCallRestrictCause(int);
+ method public void setEmergencyCallRouting(int);
method public void setEmergencyServiceCategories(int);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
@@ -6116,7 +6118,6 @@ package android.telephony.ims {
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMayHandover(int, int);
- method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -6127,6 +6128,7 @@ package android.telephony.ims {
method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
+ method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionRttMessageReceived(java.lang.String);
method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionRttModifyResponseReceived(int);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c70a397b4aca..7cfa58fb7bba 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -24,7 +24,9 @@ import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
import "frameworks/base/core/proto/android/app/enums.proto";
import "frameworks/base/core/proto/android/app/job/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/enums.proto";
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
+import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
import "frameworks/base/core/proto/android/server/enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -126,7 +128,7 @@ message Atom {
PhoneStateChanged phone_state_changed = 95;
LowMemReported low_mem_reported = 81;
NetworkDnsEventReported network_dns_event_reported = 116;
-
+ DataStallEvent data_stall_event = 121;
}
// Pulled events will start at field 10000.
@@ -2066,3 +2068,25 @@ message NetworkDnsEventReported {
optional int32 latency_micros = 3;
}
+/**
+ * Logs when a data stall event occurs.
+ *
+ * Log from:
+ * frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+ */
+message DataStallEvent {
+ // Data stall evaluation type.
+ // See frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+ // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*.
+ optional int32 evaluation_type = 1;
+ // See definition in data_stall_event.proto.
+ optional com.android.server.connectivity.ProbeResult validation_result = 2;
+ // See definition in data_stall_event.proto.
+ optional android.net.NetworkCapabilitiesProto.Transport network_type = 3;
+ // See definition in data_stall_event.proto.
+ optional com.android.server.connectivity.WifiData wifi_info = 4 [(log_mode) = MODE_BYTES];
+ // See definition in data_stall_event.proto.
+ optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES];
+ // See definition in data_stall_event.proto.
+ optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
+}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index e717c1e48e62..2bd813e14937 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1568,7 +1568,6 @@ Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telepho
Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
-Landroid/test/RepetitiveTest;->numIterations()I
Landroid/util/Singleton;-><init>()V
Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
@@ -3644,11 +3643,9 @@ Lcom/android/internal/telephony/SubscriptionInfoUpdater;->logd(Ljava/lang/String
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 000000000000..93a8d41936cc
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+*/
+
+package android.net;
+
+parcelable IpPrefixParcelable {
+ String address;
+ int prefixLength;
+} \ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 000000000000..af8e79b21f69
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+*/
+
+package android.net;
+
+parcelable LinkAddressParcelable {
+ String address;
+ int prefixLength;
+ int flags;
+ int scope;
+} \ No newline at end of file
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 617125b3f904..c2963fd605c0 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -191,6 +191,7 @@ public final class LinkProperties implements Parcelable {
}
setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
+ mNat64Prefix = source.mNat64Prefix;
}
}
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 000000000000..b153dc70e1b8
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.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 permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+ String ifaceName;
+ LinkAddressParcelable[] linkAddresses;
+ String[] dnses;
+ String[] pcscfs;
+ String[] validatedPrivateDnses;
+ boolean usePrivateDns;
+ String privateDnsServerName;
+ String domains;
+ RouteInfoParcelable[] routes;
+ ProxyInfoParcelable httpProxy;
+ int mtu;
+ String tcpBufferSizes;
+ IpPrefixParcelable nat64Prefix;
+ LinkPropertiesParcelable[] stackedLinks;
+} \ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 000000000000..59fd8467b820
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+*/
+
+package android.net;
+
+parcelable ProxyInfoParcelable {
+ String host;
+ int port;
+ String[] exclusionList;
+ String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 000000000000..15bcdcfc2000
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+ IpPrefixParcelable destination;
+ String gatewayAddr;
+ String ifaceName;
+ int type;
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
index d7e5b2761e58..b932d2197f85 100644
--- a/core/java/android/net/ipmemorystore/NetworkAttributes.java
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* A POD object to represent attributes of a single L2 network entry.
@@ -207,4 +208,52 @@ public class NetworkAttributes {
public int hashCode() {
return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
}
+
+ /** Pretty print */
+ @Override
+ public String toString() {
+ final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
+ final ArrayList<String> nullFields = new ArrayList<>();
+
+ if (null != assignedV4Address) {
+ resultJoiner.add("assignedV4Addr :");
+ resultJoiner.add(assignedV4Address.toString());
+ } else {
+ nullFields.add("assignedV4Addr");
+ }
+
+ if (null != groupHint) {
+ resultJoiner.add("groupHint :");
+ resultJoiner.add(groupHint);
+ } else {
+ nullFields.add("groupHint");
+ }
+
+ if (null != dnsAddresses) {
+ resultJoiner.add("dnsAddr : [");
+ for (final InetAddress addr : dnsAddresses) {
+ resultJoiner.add(addr.getHostAddress());
+ }
+ resultJoiner.add("]");
+ } else {
+ nullFields.add("dnsAddr");
+ }
+
+ if (null != mtu) {
+ resultJoiner.add("mtu :");
+ resultJoiner.add(mtu.toString());
+ } else {
+ nullFields.add("mtu");
+ }
+
+ if (!nullFields.isEmpty()) {
+ resultJoiner.add("; Null fields : [");
+ for (final String field : nullFields) {
+ resultJoiner.add(field);
+ }
+ resultJoiner.add("]");
+ }
+
+ return resultJoiner.toString();
+ }
}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
index 0cb37e9f75b4..d040dcc3d608 100644
--- a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -128,4 +128,19 @@ public class SameL3NetworkResponse {
public int hashCode() {
return Objects.hash(l2Key1, l2Key2, confidence);
}
+
+ @Override
+ /** Pretty print */
+ public String toString() {
+ switch (getNetworkSameness()) {
+ case NETWORK_SAME:
+ return "\"" + l2Key1 + "\" same L3 network as \"" + l2Key2 + "\"";
+ case NETWORK_DIFFERENT:
+ return "\"" + l2Key1 + "\" different L3 network from \"" + l2Key2 + "\"";
+ case NETWORK_NEVER_CONNECTED:
+ return "\"" + l2Key1 + "\" can't be tested against \"" + l2Key2 + "\"";
+ default:
+ return "Buggy sameness value ? \"" + l2Key1 + "\", \"" + l2Key2 + "\"";
+ }
+ }
}
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
index 5b016ec55ae1..95e504224ac7 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/core/java/android/net/ipmemorystore/Status.java
@@ -26,6 +26,8 @@ import android.annotation.NonNull;
public class Status {
public static final int SUCCESS = 0;
+ public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -1;
+
public final int resultCode;
public Status(final int resultCode) {
@@ -47,4 +49,14 @@ public class Status {
public boolean isSuccess() {
return SUCCESS == resultCode;
}
+
+ /** Pretty print */
+ @Override
+ public String toString() {
+ switch (resultCode) {
+ case SUCCESS: return "SUCCESS";
+ case ERROR_DATABASE_CANNOT_BE_OPENED: return "DATABASE CANNOT BE OPENED";
+ default: return "Unknown value ?!";
+ }
+ }
}
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/core/java/android/net/ipmemorystore/Utils.java
new file mode 100644
index 000000000000..73d8c83acdd9
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Utils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/** {@hide} */
+public class Utils {
+ /** Pretty print */
+ public static String blobToString(final Blob blob) {
+ final StringBuilder sb = new StringBuilder("Blob : [");
+ if (blob.data.length <= 24) {
+ appendByteArray(sb, blob.data, 0, blob.data.length);
+ } else {
+ appendByteArray(sb, blob.data, 0, 16);
+ sb.append("...");
+ appendByteArray(sb, blob.data, blob.data.length - 8, blob.data.length);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ // Adds the hex representation of the array between the specified indices (inclusive, exclusive)
+ private static void appendByteArray(@NonNull final StringBuilder sb, @NonNull final byte[] ar,
+ final int from, final int to) {
+ for (int i = from; i < to; ++i) {
+ sb.append(String.format("%02X", ar[i]));
+ }
+ }
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index b15a4d3170b3..cbb3909a5536 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -114,7 +114,6 @@ public class BugreportManager {
}
}
- // TODO(b/111441001) Connect up with BugreportListener methods.
private final class DumpstateListener extends IDumpstateListener.Stub
implements DeathRecipient {
private final BugreportListener mListener;
@@ -130,35 +129,35 @@ public class BugreportManager {
@Override
public void onProgress(int progress) throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onProgress(progress);
}
@Override
public void onError(int errorCode) throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onError(errorCode);
}
@Override
public void onFinished(long durationMs, String title, String description)
throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onFinished(durationMs, title, description);
}
// Old methods; should go away
@Override
public void onProgressUpdated(int progress) throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
@Override
public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
@Override
public void onSectionComplete(String title, int status, int size, int durationMs)
throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
}
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fdd74882eb39..8ced7225b0d4 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -356,16 +356,6 @@ interface INetworkManagementService
void removeVpnUidRanges(int netId, in UidRange[] ranges);
/**
- * Start the clatd (464xlat) service on the given interface.
- */
- void startClatd(String interfaceName);
-
- /**
- * Stop the clatd (464xlat) service on the given interface.
- */
- void stopClatd(String interfaceName);
-
- /**
* Start listening for mobile activity state changes.
*/
void registerNetworkActivityListener(INetworkActivityListener listener);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 723289005651..f2259b045c0a 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -28,6 +28,7 @@ import android.content.res.XmlResourceParser;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -37,6 +38,9 @@ import android.widget.FrameLayout;
import com.android.internal.R;
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -71,6 +75,10 @@ public abstract class LayoutInflater {
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+ = "view.precompiled_layout_enabled";
+ private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
/** Empty stack trace used to avoid log spam in re-throw exceptions. */
private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
@@ -92,6 +100,13 @@ public abstract class LayoutInflater {
private Factory2 mPrivateFactory;
private Filter mFilter;
+ // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+ // inflating from the XML resource.
+ private boolean mUseCompiledView;
+ // This variable holds the classloader that will be used to look for precompiled layouts. The
+ // The classloader includes the generated compiled_view.dex file.
+ private ClassLoader mPrecompiledClassLoader;
+
@UnsupportedAppUsage
final Object[] mConstructorArgs = new Object[2];
@@ -214,6 +229,7 @@ public abstract class LayoutInflater {
*/
protected LayoutInflater(Context context) {
mContext = context;
+ initPrecompiledViews();
}
/**
@@ -230,6 +246,7 @@ public abstract class LayoutInflater {
mFactory2 = original.mFactory2;
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
+ initPrecompiledViews();
}
/**
@@ -371,6 +388,29 @@ public abstract class LayoutInflater {
}
}
+ private void initPrecompiledViews() {
+ try {
+ mUseCompiledView =
+ SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+ if (mUseCompiledView) {
+ mPrecompiledClassLoader = mContext.getClassLoader();
+ String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+ if (new File(dexFile).exists()) {
+ mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+ } else {
+ // If the precompiled layout file doesn't exist, then disable precompiled
+ // layouts.
+ mUseCompiledView = false;
+ }
+ }
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+ }
+ mUseCompiledView = false;
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
@@ -427,10 +467,14 @@ public abstract class LayoutInflater {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
- + Integer.toHexString(resource) + ")");
+ + Integer.toHexString(resource) + ")");
}
- final XmlResourceParser parser = res.getLayout(resource);
+ View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+ if (view != null) {
+ return view;
+ }
+ XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
@@ -438,6 +482,73 @@ public abstract class LayoutInflater {
}
}
+ private @Nullable
+ View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+ boolean attachToRoot) {
+ if (!mUseCompiledView) {
+ return null;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+ // Try to inflate using a precompiled layout.
+ String pkg = res.getResourcePackageName(resource);
+ String layout = res.getResourceEntryName(resource);
+
+ try {
+ Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+ Method inflater = clazz.getMethod(layout, Context.class, int.class);
+ View view = (View) inflater.invoke(null, mContext, resource);
+
+ if (view != null && root != null) {
+ // We were able to use the precompiled inflater, but now we need to do some work to
+ // attach the view to the root correctly.
+ XmlResourceParser parser = res.getLayout(resource);
+ try {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+ advanceToRootNode(parser);
+ ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+ if (attachToRoot) {
+ root.addView(view, params);
+ } else {
+ view.setLayoutParams(params);
+ }
+ } finally {
+ parser.close();
+ }
+ }
+
+ return view;
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to use precompiled view", e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return null;
+ }
+
+ /**
+ * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+ * found.
+ */
+ private void advanceToRootNode(XmlPullParser parser)
+ throws InflateException, IOException, XmlPullParserException {
+ // Look for the root node.
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription()
+ + ": No start tag found!");
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified XML node. Throws
* {@link InflateException} if there is an error.
@@ -471,18 +582,7 @@ public abstract class LayoutInflater {
View result = root;
try {
- // Look for the root node.
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(parser.getPositionDescription()
- + ": No start tag found!");
- }
-
+ advanceToRootNode(parser);
final String name = parser.getName();
if (DEBUG) {
@@ -985,82 +1085,85 @@ public abstract class LayoutInflater {
+ "reference. The layout ID " + value + " is not valid.");
}
- final XmlResourceParser childParser = context.getResources().getLayout(layout);
+ final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+ (ViewGroup) parent, /*attachToRoot=*/true);
+ if (precompiled == null) {
+ final XmlResourceParser childParser = context.getResources().getLayout(layout);
- try {
- final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
- while ((type = childParser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty.
- }
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(childParser.getPositionDescription() +
- ": No start tag found!");
- }
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
- final String childName = childParser.getName();
+ final String childName = childParser.getName();
- if (TAG_MERGE.equals(childName)) {
- // The <merge> tag doesn't support android:theme, so
- // nothing special to do here.
- rInflate(childParser, parent, context, childAttrs, false);
- } else {
- final View view = createViewFromTag(parent, childName,
- context, childAttrs, hasThemeOverride);
- final ViewGroup group = (ViewGroup) parent;
-
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.Include);
- final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
- final int visibility = a.getInt(R.styleable.Include_visibility, -1);
- a.recycle();
-
- // We try to load the layout params set in the <include /> tag.
- // If the parent can't generate layout params (ex. missing width
- // or height for the framework ViewGroups, though this is not
- // necessarily true of all ViewGroups) then we expect it to throw
- // a runtime exception.
- // We catch this exception and set localParams accordingly: true
- // means we successfully loaded layout params from the <include>
- // tag, false means we need to rely on the included layout params.
- ViewGroup.LayoutParams params = null;
- try {
- params = group.generateLayoutParams(attrs);
- } catch (RuntimeException e) {
- // Ignore, just fail over to child attrs.
- }
- if (params == null) {
- params = group.generateLayoutParams(childAttrs);
- }
- view.setLayoutParams(params);
+ if (TAG_MERGE.equals(childName)) {
+ // The <merge> tag doesn't support android:theme, so
+ // nothing special to do here.
+ rInflate(childParser, parent, context, childAttrs, false);
+ } else {
+ final View view = createViewFromTag(parent, childName,
+ context, childAttrs, hasThemeOverride);
+ final ViewGroup group = (ViewGroup) parent;
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Include);
+ final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+ a.recycle();
+
+ // We try to load the layout params set in the <include /> tag.
+ // If the parent can't generate layout params (ex. missing width
+ // or height for the framework ViewGroups, though this is not
+ // necessarily true of all ViewGroups) then we expect it to throw
+ // a runtime exception.
+ // We catch this exception and set localParams accordingly: true
+ // means we successfully loaded layout params from the <include>
+ // tag, false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ // Ignore, just fail over to child attrs.
+ }
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
- // Inflate all children.
- rInflateChildren(childParser, view, childAttrs, true);
+ // Inflate all children.
+ rInflateChildren(childParser, view, childAttrs, true);
- if (id != View.NO_ID) {
- view.setId(id);
- }
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
- switch (visibility) {
- case 0:
- view.setVisibility(View.VISIBLE);
- break;
- case 1:
- view.setVisibility(View.INVISIBLE);
- break;
- case 2:
- view.setVisibility(View.GONE);
- break;
- }
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
+ }
- group.addView(view);
+ group.addView(view);
+ }
+ } finally {
+ childParser.close();
}
- } finally {
- childParser.close();
}
-
LayoutInflater.consumeChildElements(parser);
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 6e5751abbc40..00a267c20342 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -43,6 +43,8 @@ import android.provider.ContactsContract;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.google.android.textclassifier.AnnotatorModel;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -91,7 +93,7 @@ public final class TextClassifierImpl implements TextClassifier {
@GuardedBy("mLock") // Do not access outside this lock.
private ModelFile mModel;
@GuardedBy("mLock") // Do not access outside this lock.
- private TextClassifierImplNative mNative;
+ private AnnotatorModel mNative;
private final Object mLoggerLock = new Object();
@GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -124,7 +126,7 @@ public final class TextClassifierImpl implements TextClassifier {
&& rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = ZonedDateTime.now();
- final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales());
+ final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
final int start;
final int end;
if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -133,7 +135,7 @@ public final class TextClassifierImpl implements TextClassifier {
} else {
final int[] startEnd = nativeImpl.suggestSelection(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.SelectionOptions(localesString));
+ new AnnotatorModel.SelectionOptions(localesString));
start = startEnd[0];
end = startEnd[1];
}
@@ -141,10 +143,10 @@ public final class TextClassifierImpl implements TextClassifier {
&& start >= 0 && end <= string.length()
&& start <= request.getStartIndex() && end >= request.getEndIndex()) {
final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
nativeImpl.classifyText(
string, start, end,
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -183,11 +185,11 @@ public final class TextClassifierImpl implements TextClassifier {
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = request.getReferenceTime() != null
? request.getReferenceTime() : ZonedDateTime.now();
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
getNative(request.getDefaultLocales())
.classifyText(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -227,17 +229,17 @@ public final class TextClassifierImpl implements TextClassifier {
? request.getEntityConfig().resolveEntityListModifications(
getEntitiesForHints(request.getEntityConfig().getHints()))
: mSettings.getEntityListDefault();
- final TextClassifierImplNative nativeImpl =
+ final AnnotatorModel nativeImpl =
getNative(request.getDefaultLocales());
- final TextClassifierImplNative.AnnotatedSpan[] annotations =
+ final AnnotatorModel.AnnotatedSpan[] annotations =
nativeImpl.annotate(
textString,
- new TextClassifierImplNative.AnnotationOptions(
+ new AnnotatorModel.AnnotationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
concatenateLocales(request.getDefaultLocales())));
- for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
- final TextClassifierImplNative.ClassificationResult[] results =
+ for (AnnotatorModel.AnnotatedSpan span : annotations) {
+ final AnnotatorModel.ClassificationResult[] results =
span.getClassification();
if (results.length == 0
|| !entitiesToIdentify.contains(results[0].getCollection())) {
@@ -296,7 +298,7 @@ public final class TextClassifierImpl implements TextClassifier {
}
}
- private TextClassifierImplNative getNative(LocaleList localeList)
+ private AnnotatorModel getNative(LocaleList localeList)
throws FileNotFoundException {
synchronized (mLock) {
localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -309,7 +311,7 @@ public final class TextClassifierImpl implements TextClassifier {
destroyNativeIfExistsLocked();
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- mNative = new TextClassifierImplNative(fd.getFd());
+ mNative = new AnnotatorModel(fd.getFd());
closeAndLogError(fd);
mModel = bestModel;
}
@@ -397,14 +399,14 @@ public final class TextClassifierImpl implements TextClassifier {
}
private TextClassification createClassificationResult(
- TextClassifierImplNative.ClassificationResult[] classifications,
+ AnnotatorModel.ClassificationResult[] classifications,
String text, int start, int end, @Nullable Instant referenceTime) {
final String classifiedText = text.substring(start, end);
final TextClassification.Builder builder = new TextClassification.Builder()
.setText(classifiedText);
final int size = classifications.length;
- TextClassifierImplNative.ClassificationResult highestScoringResult = null;
+ AnnotatorModel.ClassificationResult highestScoringResult = null;
float highestScore = Float.MIN_VALUE;
for (int i = 0; i < size; i++) {
builder.setEntityType(classifications[i].getCollection(),
@@ -467,9 +469,9 @@ public final class TextClassifierImpl implements TextClassifier {
try {
final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
file, ParcelFileDescriptor.MODE_READ_ONLY);
- final int version = TextClassifierImplNative.getVersion(modelFd.getFd());
+ final int version = AnnotatorModel.getVersion(modelFd.getFd());
final String supportedLocalesStr =
- TextClassifierImplNative.getLocales(modelFd.getFd());
+ AnnotatorModel.getLocales(modelFd.getFd());
if (supportedLocalesStr.isEmpty()) {
Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
return null;
@@ -657,7 +659,7 @@ public final class TextClassifierImpl implements TextClassifier {
public static List<LabeledIntent> create(
Context context,
@Nullable Instant referenceTime,
- TextClassifierImplNative.ClassificationResult classification,
+ AnnotatorModel.ClassificationResult classification,
String text) {
final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
text = text.trim();
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
deleted file mode 100644
index 3d4c8f2863ea..000000000000
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2017 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.view.textclassifier;
-
-import android.content.res.AssetFileDescriptor;
-
-/**
- * Java wrapper for TextClassifier native library interface. This library is used for detecting
- * entities in text.
- */
-final class TextClassifierImplNative {
-
- static {
- System.loadLibrary("textclassifier");
- }
-
- private final long mModelPtr;
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file descriptor.
- */
- TextClassifierImplNative(int fd) {
- mModelPtr = nativeNew(fd);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from file descriptor.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file path.
- */
- TextClassifierImplNative(String path) {
- mModelPtr = nativeNewFromPath(path);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from given file.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * an AssetFileDescriptor.
- */
- TextClassifierImplNative(AssetFileDescriptor afd) {
- mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException(
- "Couldn't initialize TC from given AssetFileDescriptor");
- }
- }
-
- /**
- * Given a string context and current selection, computes the SmartSelection suggestion.
- *
- * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is
- * the character index where the selection begins, and selectionEnd is the index of one
- * character past the selection span.
- *
- * <p>The return value is an array of two ints: suggested selection beginning and end, with the
- * same semantics as the input selectionBeginning and selectionEnd.
- */
- public int[] suggestSelection(
- String context, int selectionBegin, int selectionEnd, SelectionOptions options) {
- return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Given a string context and current selection, classifies the type of the selected text.
- *
- * <p>The begin and end params are character indices in the context string.
- *
- * <p>Returns an array of ClassificationResult objects with the probability scores for different
- * collections.
- */
- public ClassificationResult[] classifyText(
- String context, int selectionBegin, int selectionEnd, ClassificationOptions options) {
- return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Annotates given input text. The annotations should cover the whole input context except for
- * whitespaces, and are sorted by their position in the context string.
- */
- public AnnotatedSpan[] annotate(String text, AnnotationOptions options) {
- return nativeAnnotate(mModelPtr, text, options);
- }
-
- /** Frees up the allocated memory. */
- public void close() {
- nativeClose(mModelPtr);
- }
-
- /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */
- public static String getLocales(int fd) {
- return nativeGetLocales(fd);
- }
-
- /** Returns the version of the model. */
- public static int getVersion(int fd) {
- return nativeGetVersion(fd);
- }
-
- /** Represents a datetime parsing result from classifyText calls. */
- public static final class DatetimeResult {
- static final int GRANULARITY_YEAR = 0;
- static final int GRANULARITY_MONTH = 1;
- static final int GRANULARITY_WEEK = 2;
- static final int GRANULARITY_DAY = 3;
- static final int GRANULARITY_HOUR = 4;
- static final int GRANULARITY_MINUTE = 5;
- static final int GRANULARITY_SECOND = 6;
-
- private final long mTimeMsUtc;
- private final int mGranularity;
-
- DatetimeResult(long timeMsUtc, int granularity) {
- mGranularity = granularity;
- mTimeMsUtc = timeMsUtc;
- }
-
- public long getTimeMsUtc() {
- return mTimeMsUtc;
- }
-
- public int getGranularity() {
- return mGranularity;
- }
- }
-
- /** Represents a result of classifyText method call. */
- public static final class ClassificationResult {
- private final String mCollection;
- private final float mScore;
- private final DatetimeResult mDatetimeResult;
-
- ClassificationResult(
- String collection, float score, DatetimeResult datetimeResult) {
- mCollection = collection;
- mScore = score;
- mDatetimeResult = datetimeResult;
- }
-
- public String getCollection() {
- if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) {
- switch (mDatetimeResult.getGranularity()) {
- case DatetimeResult.GRANULARITY_HOUR:
- // fall through
- case DatetimeResult.GRANULARITY_MINUTE:
- // fall through
- case DatetimeResult.GRANULARITY_SECOND:
- return TextClassifier.TYPE_DATE_TIME;
- default:
- return TextClassifier.TYPE_DATE;
- }
- }
- return mCollection;
- }
-
- public float getScore() {
- return mScore;
- }
-
- public DatetimeResult getDatetimeResult() {
- return mDatetimeResult;
- }
- }
-
- /** Represents a result of Annotate call. */
- public static final class AnnotatedSpan {
- private final int mStartIndex;
- private final int mEndIndex;
- private final ClassificationResult[] mClassification;
-
- AnnotatedSpan(
- int startIndex, int endIndex, ClassificationResult[] classification) {
- mStartIndex = startIndex;
- mEndIndex = endIndex;
- mClassification = classification;
- }
-
- public int getStartIndex() {
- return mStartIndex;
- }
-
- public int getEndIndex() {
- return mEndIndex;
- }
-
- public ClassificationResult[] getClassification() {
- return mClassification;
- }
- }
-
- /** Represents options for the suggestSelection call. */
- public static final class SelectionOptions {
- private final String mLocales;
-
- SelectionOptions(String locales) {
- mLocales = locales;
- }
-
- public String getLocales() {
- return mLocales;
- }
- }
-
- /** Represents options for the classifyText call. */
- public static final class ClassificationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- /** Represents options for the Annotate call. */
- public static final class AnnotationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- private static native long nativeNew(int fd);
-
- private static native long nativeNewFromPath(String path);
-
- private static native long nativeNewFromAssetFileDescriptor(
- AssetFileDescriptor afd, long offset, long size);
-
- private static native int[] nativeSuggestSelection(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- SelectionOptions options);
-
- private static native ClassificationResult[] nativeClassifyText(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- ClassificationOptions options);
-
- private static native AnnotatedSpan[] nativeAnnotate(
- long context, String text, AnnotationOptions options);
-
- private static native void nativeClose(long context);
-
- private static native String nativeGetLocales(int fd);
-
- private static native int nativeGetVersion(int fd);
-}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a30f77e..b2d3651079e1 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -281,15 +281,18 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName
std::unique_ptr<NativeCode> code;
bool needs_native_bridge = false;
+ char* nativeloader_error_msg = nullptr;
void* handle = OpenNativeLibrary(env,
sdkVersion,
pathStr.c_str(),
classLoader,
libraryPath,
&needs_native_bridge,
- &g_error_msg);
+ &nativeloader_error_msg);
if (handle == nullptr) {
+ g_error_msg = nativeloader_error_msg;
+ NativeLoaderFreeErrorMessage(nativeloader_error_msg);
ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
pathStr.c_str(),
g_error_msg.c_str());
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
new file mode 100644
index 000000000000..b70bb677d7a0
--- /dev/null
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package com.android.server.connectivity;
+option java_multiple_files = true;
+option java_outer_classname = "DataStallEventProto";
+
+enum ProbeResult {
+ UNKNOWN = 0;
+ VALID = 1;
+ INVALID = 2;
+ PORTAL = 3;
+}
+
+enum ApBand {
+ AP_BAND_UNKNOWN = 0;
+ AP_BAND_2GHZ = 1;
+ AP_BAND_5GHZ = 2;
+}
+
+// Refer to definition in ServiceState.java.
+enum RadioTech {
+ RADIO_TECHNOLOGY_UNKNOWN = 0;
+ RADIO_TECHNOLOGY_GPRS = 1;
+ RADIO_TECHNOLOGY_EDGE = 2;
+ RADIO_TECHNOLOGY_UMTS = 3;
+ RADIO_TECHNOLOGY_IS95A = 4;
+ RADIO_TECHNOLOGY_IS95B = 5;
+ RADIO_TECHNOLOGY_1xRTT = 6;
+ RADIO_TECHNOLOGY_EVDO_0 = 7;
+ RADIO_TECHNOLOGY_EVDO_A = 8;
+ RADIO_TECHNOLOGY_HSDPA = 9;
+ RADIO_TECHNOLOGY_HSUPA = 10;
+ RADIO_TECHNOLOGY_HSPA = 11;
+ RADIO_TECHNOLOGY_EVDO_B = 12;
+ RADIO_TECHNOLOGY_EHRPD = 13;
+ RADIO_TECHNOLOGY_LTE = 14;
+ RADIO_TECHNOLOGY_HSPAP = 15;
+ RADIO_TECHNOLOGY_GSM = 16;
+ RADIO_TECHNOLOGY_TD_SCDMA = 17;
+ RADIO_TECHNOLOGY_IWLAN = 18;
+ RADIO_TECHNOLOGY_LTE_CA = 19;
+ RADIO_TECHNOLOGY_NR = 20;
+}
+
+// Cellular specific information.
+message CellularData {
+ // Indicate the radio technology at the time of data stall suspected.
+ optional RadioTech rat_type = 1;
+ // True if device is in roaming network at the time of data stall suspected.
+ optional bool is_roaming = 2;
+ // Registered network MccMnc when data stall happen
+ optional string network_mccmnc = 3;
+ // Indicate the SIM card carrier.
+ optional string sim_mccmnc = 4;
+ // Signal strength level at the time of data stall suspected.
+ optional int32 signal_strength = 5;
+}
+
+// Wifi specific information.
+message WifiData {
+ // Signal strength at the time of data stall suspected.
+ // RSSI range is between -55 to -110.
+ optional int32 signal_strength = 1;
+ // AP band.
+ optional ApBand wifi_band = 2;
+}
+
+message DnsEvent {
+ // The dns return code.
+ repeated int32 dns_return_code = 1;
+ // Indicate the timestamp of the dns event.
+ repeated int64 dns_time = 2;
+} \ No newline at end of file
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 6ce81481c1d7..035ee108c6da 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -39,9 +39,6 @@ prebuilt_etc {
name: "privapp-permissions-platform.xml",
sub_dir: "permissions",
src: "privapp-permissions-platform.xml",
- required: [
- "privapp_whitelist_com.android.settings.intelligence",
- ],
}
prebuilt_etc {
@@ -86,6 +83,7 @@ prebuilt_etc {
prebuilt_etc {
name: "privapp_whitelist_com.android.settings.intelligence",
+ product_specific: true,
sub_dir: "permissions",
src: "com.android.settings.intelligence.xml",
filename_from_src: true,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 73c10d238a60..afe791344f7b 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -182,11 +182,11 @@
code to link against. -->
<library name="android.test.base"
- file="/system/framework/android.test.base.impl.jar" />
+ file="/system/framework/android.test.base.jar" />
<library name="android.test.mock"
- file="/system/framework/android.test.mock.impl.jar" />
+ file="/system/framework/android.test.mock.jar" />
<library name="android.test.runner"
- file="/system/framework/android.test.runner.impl.jar" />
+ file="/system/framework/android.test.runner.jar" />
<!-- In BOOT_JARS historically, and now added to legacy applications. -->
<library name="android.hidl.base-V1.0-java"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index afb978174784..2d7471d9aca5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1953,8 +1953,7 @@ public class BugreportProgressService extends Service {
@Override
public void onProgress(int progress) throws RemoteException {
- // TODO(b/111441001): change max argument?
- updateProgressInfo(progress, CAPPED_MAX);
+ updateProgressInfo(progress, 100 /* progress is already a percentage; so max = 100 */);
}
@Override
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 295b3d8bc979..be9ba4351056 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -26,6 +26,6 @@ LOCAL_PACKAGE_NAME := PacProcessor
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
-LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor libpac
+LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
include $(BUILD_PACKAGE)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d0666b98c0e0..d6f3e2ba4835 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4879,7 +4879,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
- mContext, mTrackerHandler, new NetworkMisc(networkMisc), this);
+ mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 00b13207de2c..600a6ae0babd 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -17,13 +17,11 @@
package com.android.server;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
@@ -40,6 +38,7 @@ import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
+
import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
@@ -53,11 +52,9 @@ import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENAB
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
-import android.net.TetherStatsParcel;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
@@ -69,18 +66,15 @@ import android.net.NetworkPolicyManager;
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.TetherStatsParcel;
import android.net.UidRange;
-import android.net.UidRangeParcel;
import android.net.util.NetdService;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
-import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -91,12 +85,7 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
-import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -109,13 +98,11 @@ import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
-import com.android.server.NativeDaemonConnector.Command;
-import com.android.server.NativeDaemonConnector.SensitiveArg;
+
import com.google.android.collect.Maps;
import java.io.BufferedReader;
import java.io.DataInputStream;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
@@ -123,15 +110,11 @@ import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
/**
@@ -2147,28 +2130,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
- public void startClatd(String interfaceName) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.clatdStart(interfaceName);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void stopClatd(String interfaceName) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.clatdStop(interfaceName);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
public void registerNetworkActivityListener(INetworkActivityListener listener) {
mNetworkActivityListeners.register(listener);
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 6596d27d021e..9d9b1cfdf6e2 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,8 +16,9 @@
package com.android.server.connectivity;
-import android.net.InterfaceConfiguration;
import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -59,6 +60,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
NetworkInfo.State.SUSPENDED,
};
+ private final INetd mNetd;
private final INetworkManagementService mNMService;
// The network we're running on, and its type.
@@ -76,7 +78,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
private String mIface;
private State mState = State.IDLE;
- public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+ public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+ mNetd = netd;
mNMService = nmService;
mNetwork = nai;
}
@@ -140,7 +143,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
return;
}
try {
- mNMService.startClatd(baseIface);
+ mNetd.clatdStart(baseIface);
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error starting clatd on " + baseIface, e);
}
@@ -162,7 +165,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
*/
private void enterStoppingState() {
try {
- mNMService.stopClatd(mBaseIface);
+ mNetd.clatdStop(mBaseIface);
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
}
@@ -204,7 +207,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
Slog.e(TAG, "startClat: Can't start clat on null interface");
return;
}
- // TODO: should we only do this if mNMService.startClatd() succeeds?
+ // TODO: should we only do this if mNetd.clatdStart() succeeds?
Slog.i(TAG, "Starting clatd on " + baseIface);
enterStartingState(baseIface);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 54c89aa04111..9ea73fbb1882 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import android.content.Context;
+import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
import android.net.Network;
@@ -239,12 +240,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
private final ConnectivityService mConnService;
+ private final INetd mNetd;
+ private final INetworkManagementService mNMS;
private final Context mContext;
private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
- NetworkMisc misc, ConnectivityService connService) {
+ NetworkMisc misc, ConnectivityService connService, INetd netd,
+ INetworkManagementService nms) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -253,6 +257,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
networkCapabilities = nc;
currentScore = score;
mConnService = connService;
+ mNetd = netd;
+ mNMS = nms;
mContext = context;
mHandler = handler;
networkMisc = misc;
@@ -587,18 +593,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public void updateClat(INetworkManagementService netd) {
if (Nat464Xlat.requiresClat(this)) {
- maybeStartClat(netd);
+ maybeStartClat();
} else {
maybeStopClat();
}
}
/** Ensure clat has started for this network. */
- public void maybeStartClat(INetworkManagementService netd) {
+ public void maybeStartClat() {
if (clatd != null && clatd.isStarted()) {
return;
}
- clatd = new Nat464Xlat(netd, this);
+ clatd = new Nat464Xlat(this, mNetd, mNMS);
clatd.start();
}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810f2d76..97896889f243 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@ public class PacManager {
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
+ return;
}
try {
mProxyService.setPacFile(script);
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
new file mode 100644
index 000000000000..eaab6507e8d4
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package com.android.server.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Encapsulating class for using the SQLite database backing the memory store.
+ *
+ * This class groups together the contracts and the SQLite helper used to
+ * use the database.
+ *
+ * @hide
+ */
+public class IpMemoryStoreDatabase {
+ /**
+ * Contract class for the Network Attributes table.
+ */
+ public static class NetworkAttributesContract {
+ public static final String TABLENAME = "NetworkAttributes";
+
+ public static final String COLNAME_L2KEY = "l2Key";
+ public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+ public static final String COLNAME_EXPIRYDATE = "expiryDate";
+ // Milliseconds since the Epoch, in true Java style
+ public static final String COLTYPE_EXPIRYDATE = "BIGINT";
+
+ public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
+ public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
+
+ // Please note that the group hint is only a *hint*, hence its name. The client can offer
+ // this information to nudge the grouping in the decision it thinks is right, but it can't
+ // decide for the memory store what is the same L3 network.
+ public static final String COLNAME_GROUPHINT = "groupHint";
+ public static final String COLTYPE_GROUPHINT = "TEXT";
+
+ public static final String COLNAME_DNSADDRESSES = "dnsAddresses";
+ // Stored in marshalled form as is
+ public static final String COLTYPE_DNSADDRESSES = "BLOB";
+
+ public static final String COLNAME_MTU = "mtu";
+ public static final String COLTYPE_MTU = "INTEGER";
+
+ public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+ + TABLENAME + " ("
+ + COLNAME_L2KEY + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+ + COLNAME_EXPIRYDATE + " " + COLTYPE_EXPIRYDATE + ", "
+ + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
+ + COLNAME_GROUPHINT + " " + COLTYPE_GROUPHINT + ", "
+ + COLNAME_DNSADDRESSES + " " + COLTYPE_DNSADDRESSES + ", "
+ + COLNAME_MTU + " " + COLTYPE_MTU + ")";
+ public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+ }
+
+ /**
+ * Contract class for the Private Data table.
+ */
+ public static class PrivateDataContract {
+ public static final String TABLENAME = "PrivateData";
+
+ public static final String COLNAME_L2KEY = "l2Key";
+ public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+ public static final String COLNAME_CLIENT = "client";
+ public static final String COLTYPE_CLIENT = "TEXT NOT NULL";
+
+ public static final String COLNAME_DATANAME = "dataName";
+ public static final String COLTYPE_DATANAME = "TEXT NOT NULL";
+
+ public static final String COLNAME_DATA = "data";
+ public static final String COLTYPE_DATA = "BLOB NOT NULL";
+
+ public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+ + TABLENAME + " ("
+ + COLNAME_L2KEY + " " + COLTYPE_L2KEY + ", "
+ + COLNAME_CLIENT + " " + COLTYPE_CLIENT + ", "
+ + COLNAME_DATANAME + " " + COLTYPE_DATANAME + ", "
+ + COLNAME_DATA + " " + COLTYPE_DATA + ", "
+ + "PRIMARY KEY ("
+ + COLNAME_L2KEY + ", "
+ + COLNAME_CLIENT + ", "
+ + COLNAME_DATANAME + "))";
+ public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+ }
+
+ // To save memory when the DB is not used, close it after 30s of inactivity. This is
+ // determined manually based on what feels right.
+ private static final long IDLE_CONNECTION_TIMEOUT_MS = 30_000;
+
+ /** The SQLite DB helper */
+ public static class DbHelper extends SQLiteOpenHelper {
+ // Update this whenever changing the schema.
+ private static final int SCHEMA_VERSION = 1;
+ private static final String DATABASE_FILENAME = "IpMemoryStore.db";
+
+ public DbHelper(@NonNull final Context context) {
+ super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
+ setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+ }
+
+ /** Called when the database is created */
+ public void onCreate(@NonNull final SQLiteDatabase db) {
+ db.execSQL(NetworkAttributesContract.CREATE_TABLE);
+ db.execSQL(PrivateDataContract.CREATE_TABLE);
+ }
+
+ /** Called when the database is upgraded */
+ public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+ final int newVersion) {
+ // No upgrade supported yet.
+ db.execSQL(NetworkAttributesContract.DROP_TABLE);
+ db.execSQL(PrivateDataContract.DROP_TABLE);
+ onCreate(db);
+ }
+
+ /** Called when the database is downgraded */
+ public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+ final int newVersion) {
+ // Downgrades always nuke all data and recreate an empty table.
+ db.execSQL(NetworkAttributesContract.DROP_TABLE);
+ db.execSQL(PrivateDataContract.DROP_TABLE);
+ onCreate(db);
+ }
+ }
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
index c9759bf6170f..55a72190eff4 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -19,6 +19,8 @@ package com.android.server.net.ipmemorystore;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
import android.net.IIpMemoryStore;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,6 +29,10 @@ import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* Implementation for the IP memory store.
@@ -37,10 +43,75 @@ import android.net.ipmemorystore.NetworkAttributesParcelable;
* @hide
*/
public class IpMemoryStoreService extends IIpMemoryStore.Stub {
+ private static final String TAG = IpMemoryStoreService.class.getSimpleName();
+ private static final int MAX_CONCURRENT_THREADS = 4;
+
+ @NonNull
final Context mContext;
+ @Nullable
+ final SQLiteDatabase mDb;
+ @NonNull
+ final ExecutorService mExecutor;
+ /**
+ * Construct an IpMemoryStoreService object.
+ * This constructor will block on disk access to open the database.
+ * @param context the context to access storage with.
+ */
public IpMemoryStoreService(@NonNull final Context context) {
+ // Note that constructing the service will access the disk and block
+ // for some time, but it should make no difference to the clients. Because
+ // the interface is one-way, clients fire and forget requests, and the callback
+ // will get called eventually in any case, and the framework will wait for the
+ // service to be created to deliver subsequent requests.
+ // Avoiding this would mean the mDb member can't be final, which means the service would
+ // have to test for nullity, care for failure, and allow for a wait at every single access,
+ // which would make the code a lot more complex and require all methods to possibly block.
mContext = context;
+ SQLiteDatabase db;
+ final IpMemoryStoreDatabase.DbHelper helper = new IpMemoryStoreDatabase.DbHelper(context);
+ try {
+ db = helper.getWritableDatabase();
+ if (null == db) Log.e(TAG, "Unexpected null return of getWriteableDatabase");
+ } catch (final SQLException e) {
+ Log.e(TAG, "Can't open the Ip Memory Store database", e);
+ db = null;
+ } catch (final Exception e) {
+ Log.wtf(TAG, "Impossible exception Ip Memory Store database", e);
+ db = null;
+ }
+ mDb = db;
+ // The work-stealing thread pool executor will spawn threads as needed up to
+ // the max only when there is no free thread available. This generally behaves
+ // exactly like one would expect it intuitively :
+ // - When work arrives, it will spawn a new thread iff there are no available threads
+ // - When there is no work to do it will shutdown threads after a while (the while
+ // being equal to 2 seconds (not configurable) when max threads are spun up and
+ // twice as much for every one less thread)
+ // - When all threads are busy the work is enqueued and waits for any worker
+ // to become available.
+ // Because the stealing pool is made for very heavily parallel execution of
+ // small tasks that spawn others, it creates a queue per thread that in this
+ // case is overhead. However, the three behaviors above make it a superior
+ // choice to cached or fixedThreadPoolExecutor, neither of which can actually
+ // enqueue a task waiting for a thread to be free. This can probably be solved
+ // with judicious subclassing of ThreadPoolExecutor, but that's a lot of dangerous
+ // complexity for little benefit in this case.
+ mExecutor = Executors.newWorkStealingPool(MAX_CONCURRENT_THREADS);
+ }
+
+ /**
+ * Shutdown the memory store service, cancelling running tasks and dropping queued tasks.
+ *
+ * This is provided to give a way to clean up, and is meant to be available in case of an
+ * emergency shutdown.
+ */
+ public void shutdown() {
+ // By contrast with ExecutorService#shutdown, ExecutorService#shutdownNow tries
+ // to cancel the existing tasks, and does not wait for completion. It does not
+ // guarantee the threads can be terminated in any given amount of time.
+ mExecutor.shutdownNow();
+ if (mDb != null) mDb.close();
}
/**
@@ -61,7 +132,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
public void storeNetworkAttributes(@NonNull final String l2Key,
@NonNull final NetworkAttributesParcelable attributes,
@Nullable final IOnStatusListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -79,7 +150,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
@NonNull final String name, @NonNull final Blob data,
@Nullable final IOnStatusListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -99,7 +170,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
@Override
public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
@NonNull final IOnL2KeyResponseListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -114,7 +185,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
@Override
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
@NonNull final IOnSameNetworkResponseListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
new file mode 100644
index 000000000000..aa454008958d
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+package com.android.server.net.ipmemorystore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class containing the logic around the relevance value for
+ * IP Memory Store.
+ *
+ * @hide
+ */
+public class RelevanceUtils {
+ /**
+ * The relevance is a decaying value that gets lower and lower until it
+ * reaches 0 after some time passes. It follows an exponential decay law,
+ * dropping slowly at first then faster and faster, because a network is
+ * likely to be visited again if it was visited not long ago, and the longer
+ * it hasn't been visited the more likely it is that it won't be visited
+ * again. For example, a network visited on holiday should stay fresh for
+ * the duration of the holiday and persist for a while, but after the venue
+ * hasn't been visited for a while it should quickly be discarded. What
+ * should accelerate forgetting the network is extended periods without
+ * visits, so that occasional venues get discarded but regular visits keep
+ * the network relevant, even if the visits are infrequent.
+ *
+ * This function must be stable by iteration, meaning that adjusting the same value
+ * for different dates iteratively multiple times should give the same result.
+ * Formally, if f is the decay function that associates a relevance x at a date d1
+ * to the value at ulterior date d3, then for any date d2 between d1 and d3 :
+ * f(x, d3 - d1) = f(f(x, d3 - d2), d2 - d1). Intuitively, this property simply
+ * means it should be the same to compute and store back the value after two months,
+ * or to do it once after one month, store it back, and do it again after another
+ * months has passed.
+ * The pair of the relevance and date define the entire curve, so any pair
+ * of values on the curve will define the same curve. Setting one of them to a
+ * constant, so as not to have to store it, means the other one will always suffice
+ * to describe the curve. For example, only storing the date for a known, constant
+ * value of the relevance is an efficient way of remembering this information (and
+ * to compare relevances together, as f is monotonically decreasing).
+ *
+ *** Choosing the function :
+ * Functions of the kind described above are standard exponential decay functions
+ * like the ones that govern atomic decay where the value at any given date can be
+ * computed uniformly from the value at a previous date and the time elapsed since
+ * that date. It is simple to picture this kind of function as one where after a
+ * given period of time called the half-life, the relevance value will have been
+ * halved. Decay of this kind is expressed in function of the previous value by
+ * functions like
+ * f(x, t) = x * F ^ (t / L)
+ * ...where x is the value, t is the elapsed time, L is the half-life (or more
+ * generally the F-th-life) and F the decay factor (typically 0.5, hence why L is
+ * usually called the half-life). The ^ symbol here is used for exponentiation.
+ * Or, starting at a given M for t = 0 :
+ * f(t) = M * F ^ (t / L)
+ *
+ * Because a line in the store needs to become irrelevant at some point but
+ * this class of functions never go to 0, a minimum cutoff has to be chosen to
+ * represent irrelevance. The simpler way of doing this is to simply add this
+ * minimum cutoff to the computation before and removing it after.
+ * Thus the function becomes :
+ * f(x, t) = ((x + K) * F ^ (t / L)) - K
+ * ...where K is the minimum cutoff, L the half-life, and F the factor between
+ * the original x and x after its half-life. Strictly speaking using the word
+ * "half-life" implies that F = 0.5, but the relation works for any value of F.
+ *
+ * It is easy enough to check that this function satisfies the stability
+ * relation that was given above for any value of F, L and K, which become
+ * parameters that can be defined at will.
+ *
+ * relevance
+ * 1.0 |
+ * |\
+ * | \
+ * | \ (this graph rendered with L = 75 days and K = 1/40)
+ * 0.75| ',
+ * | \
+ * | '.
+ * | \.
+ * | \
+ * 0.5 | '\
+ * | ''.
+ * | ''.
+ * | ''.
+ * 0.25| '''..
+ * | '''..
+ * | ''''....
+ * | '''''..........
+ * 0 +-------------------------------------------------------''''''''''----
+ * 0 50 100 150 200 250 300 350 400 days
+ *
+ *** Choosing the parameters
+ * The maximum M is an arbitrary parameter that simply scales the curve.
+ * The tradeoff for M is pretty simple : if the relevance is going to be an
+ * integer, the bigger M is the more precision there is in the relevance.
+ * However, values of M that are easy for humans to read are preferable to
+ * help debugging, and a suitably low value may be enough to ensure there
+ * won't be integer overflows in intermediate computations.
+ * A value of 1_000_000 probably is plenty for precision, while still in the
+ * low range of what ints can represent.
+ *
+ * F and L are parameters to be chosen arbitrarily and have an impact on how
+ * fast the relevance will be decaying at first, keeping in mind that
+ * the 400 days value and the cap stay the same. In simpler words, F and L
+ * define the steepness of the curve.
+ * To keep things simple (and familiar) F is arbitrarily chosen to be 0.5, and
+ * L is set to 200 days visually to achieve the desired effect. Refer to the
+ * illustration above to get a feel of how that feels.
+ *
+ * Moreover, the memory store works on an assumption that the relevance should
+ * be capped, and that an entry with capped relevance should decay in 400 days.
+ * This is on premises that the networks a device will need to remember the
+ * longest should be networks visited about once a year.
+ * For this reason, the relevance is at the maximum M 400 days before expiry :
+ * f(M, 400 days) = 0
+ * From replacing this with the value of the function, K can then be derived
+ * from the values of M, F and L :
+ * (M + K) * F ^ (t / L) - K = 0
+ * K = M * F ^ (400 days / L) / (1 - F ^ (400 days / L))
+ * Replacing with actual values this gives :
+ * K = 1_000_000 * 0.5 ^ (400 / 200) / (1 - 0.5 ^ (400 / 200))
+ * = 1_000_000 / 3 ≈ 333_333.3
+ * This ensures the function has the desired profile, the desired value at
+ * cap, and the desired value at expiry.
+ *
+ *** Useful relations
+ * Let's define the expiry time for any given relevance x as the interval of
+ * time such as :
+ * f(x, expiry) = 0
+ * which can be rewritten
+ * ((x + K) * F ^ (expiry / L)) = K
+ * ...giving an expression of the expiry in function of the relevance x as
+ * expiry = L * logF(K / (x + K))
+ * Conversely the relevance x can be expressed in function of the expiry as
+ * x = K / F ^ (expiry / L) - K
+ * These relations are useful in utility functions.
+ *
+ *** Bumping things up
+ * The last issue therefore is to decide how to bump up the relevance. The
+ * simple approach is to simply lift up the curve a little bit by a constant
+ * normalized amount, delaying the time of expiry. For example increasing
+ * the relevance by an amount I gives :
+ * x2 = x1 + I
+ * x2 and x1 correspond to two different expiry times expiry2 and expiry1,
+ * and replacing x1 and x2 in the relation above with their expression in
+ * function of the expiry comes :
+ * K / F ^ (expiry2 / L) - K = K / F ^ (expiry1 / L) - K + I
+ * which resolves to :
+ * expiry2 = L * logF(K / (I + K / F ^ (expiry1 / L)))
+ *
+ * In this implementation, the bump is defined as 1/25th of the cap for
+ * the relevance. This means a network will be remembered for the maximum
+ * period of 400 days if connected 25 times in succession not accounting
+ * for decay. Of course decay actually happens so it will take more than 25
+ * connections for any given network to actually reach the cap, but because
+ * decay is slow at first, it is a good estimate of how fast cap happens.
+ *
+ * Specifically, it gives the following four results :
+ * - A network that a device connects to once hits irrelevance about 32.7 days after
+ * it was first registered if never connected again.
+ * - A network that a device connects to once a day at a fixed hour will hit the cap
+ * on the 27th connection.
+ * - A network that a device connects to once a week at a fixed hour will hit the cap
+ * on the 57th connection.
+ * - A network that a device connects to every day for 7 straight days then never again
+ * expires 144 days after the last connection.
+ * These metrics tend to match pretty well the requirements.
+ */
+
+ // TODO : make these constants configurable at runtime. Don't forget to build it so that
+ // changes will wipe the database, migrate the values, or otherwise make sure the relevance
+ // values are still meaningful.
+
+ // How long, in milliseconds, is a capped relevance valid for, or in other
+ // words how many milliseconds after its relevance was set to RELEVANCE_CAP does
+ // any given line expire. 400 days.
+ @VisibleForTesting
+ public static final long CAPPED_RELEVANCE_LIFETIME_MS = 400L * 24 * 60 * 60 * 1000;
+
+ // The constant that represents a normalized 1.0 value for the relevance. In other words,
+ // the cap for the relevance. This is referred to as M in the explanation above.
+ @VisibleForTesting
+ public static final int CAPPED_RELEVANCE = 1_000_000;
+
+ // The decay factor. After a half-life, the relevance will have decayed by this value.
+ // This is referred to as F in the explanation above.
+ private static final double DECAY_FACTOR = 0.5;
+
+ // The half-life. After this time, the relevance will have decayed by a factor DECAY_FACTOR.
+ // This is referred to as L in the explanation above.
+ private static final long HALF_LIFE_MS = 200L * 24 * 60 * 60 * 1000;
+
+ // The value of the frame change. This is referred to as K in the explanation above.
+ private static final double IRRELEVANCE_FLOOR =
+ CAPPED_RELEVANCE * powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS)
+ / (1 - powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS));
+
+ // How much to bump the relevance by every time a line is written to.
+ @VisibleForTesting
+ public static final int RELEVANCE_BUMP = CAPPED_RELEVANCE / 25;
+
+ // Java doesn't include a function for the logarithm in an arbitrary base, so implement it
+ private static final double LOG_DECAY_FACTOR = Math.log(DECAY_FACTOR);
+ private static double logF(final double value) {
+ return Math.log(value) / LOG_DECAY_FACTOR;
+ }
+
+ // Utility function to get a power of the decay factor, to simplify the code.
+ private static double powF(final double value) {
+ return Math.pow(DECAY_FACTOR, value);
+ }
+
+ /**
+ * Compute the value of the relevance now given an expiry date.
+ *
+ * @param expiry the date at which the column in the database expires.
+ * @return the adjusted value of the relevance for this moment in time.
+ */
+ public static int computeRelevanceForNow(final long expiry) {
+ return computeRelevanceForTargetDate(expiry, System.currentTimeMillis());
+ }
+
+ /**
+ * Compute the value of the relevance at a given date from an expiry date.
+ *
+ * Because relevance decays with time, a relevance in the past corresponds to
+ * a different relevance later.
+ *
+ * Relevance is always a positive value. 0 means not relevant at all.
+ *
+ * See the explanation at the top of this file to get the justification for this
+ * computation.
+ *
+ * @param expiry the date at which the column in the database expires.
+ * @param target the target date to adjust the relevance to.
+ * @return the adjusted value of the relevance for the target moment.
+ */
+ public static int computeRelevanceForTargetDate(final long expiry, final long target) {
+ final long delay = expiry - target;
+ if (delay >= CAPPED_RELEVANCE_LIFETIME_MS) return CAPPED_RELEVANCE;
+ if (delay <= 0) return 0;
+ return (int) (IRRELEVANCE_FLOOR / powF((float) delay / HALF_LIFE_MS) - IRRELEVANCE_FLOOR);
+ }
+
+ /**
+ * Compute the expiry duration adjusted up for a new fresh write.
+ *
+ * Every time data is written to the memory store for a given line, the
+ * relevance is bumped up by a certain amount, which will boost the priority
+ * of this line for computation of group attributes, and delay (possibly
+ * indefinitely, if the line is accessed regularly) forgetting the data stored
+ * in that line.
+ * As opposed to bumpExpiryDate, this function uses a duration from now to expiry.
+ *
+ * See the explanation at the top of this file for a justification of this computation.
+ *
+ * @param oldExpiryDuration the old expiry duration in milliseconds from now.
+ * @return the expiry duration representing a bumped up relevance value.
+ */
+ public static long bumpExpiryDuration(final long oldExpiryDuration) {
+ // L * logF(K / (I + K / F ^ (expiry1 / L))), as documented above
+ final double divisionFactor = powF(((double) oldExpiryDuration) / HALF_LIFE_MS);
+ final double oldRelevance = IRRELEVANCE_FLOOR / divisionFactor;
+ final long newDuration =
+ (long) (HALF_LIFE_MS * logF(IRRELEVANCE_FLOOR / (RELEVANCE_BUMP + oldRelevance)));
+ return Math.min(newDuration, CAPPED_RELEVANCE_LIFETIME_MS);
+ }
+
+ /**
+ * Compute the new expiry date adjusted up for a new fresh write.
+ *
+ * Every time data is written to the memory store for a given line, the
+ * relevance is bumped up by a certain amount, which will boost the priority
+ * of this line for computation of group attributes, and delay (possibly
+ * indefinitely, if the line is accessed regularly) forgetting the data stored
+ * in that line.
+ * As opposed to bumpExpiryDuration, this function takes the old timestamp and returns the
+ * new timestamp.
+ *
+ * {@see bumpExpiryDuration}, and keep in mind that the bump depends on when this is called,
+ * because the relevance decays exponentially, therefore bumping up a high relevance (for a
+ * date far in the future) is less potent than bumping up a low relevance (for a date in
+ * a close future).
+ *
+ * @param oldExpiryDate the old date of expiration.
+ * @return the new expiration date after the relevance bump.
+ */
+ public static long bumpExpiryDate(final long oldExpiryDate) {
+ final long now = System.currentTimeMillis();
+ final long newDuration = bumpExpiryDuration(oldExpiryDate - now);
+ return now + newDuration;
+ }
+}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 000000000000..5b77f543c62b
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+ /**
+ * Convert a ProxyInfo to a ProxyInfoParcelable
+ */
+ public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+ if (proxyInfo == null) {
+ return null;
+ }
+ final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+ parcel.host = proxyInfo.getHost();
+ parcel.port = proxyInfo.getPort();
+ parcel.exclusionList = proxyInfo.getExclusionList();
+ parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+ return parcel;
+ }
+
+ /**
+ * Convert a ProxyInfoParcelable to a ProxyInfo
+ */
+ public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+ }
+ }
+
+ /**
+ * Convert an IpPrefixParcelable to an IpPrefix
+ */
+ public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+ if (ipPrefix == null) {
+ return null;
+ }
+ final IpPrefixParcelable parcel = new IpPrefixParcelable();
+ parcel.address = ipPrefix.getAddress().getHostAddress();
+ parcel.prefixLength = ipPrefix.getPrefixLength();
+ return parcel;
+ }
+
+ /**
+ * Convert an IpPrefix to an IpPrefixParcelable
+ */
+ public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+ }
+
+ /**
+ * Convert a RouteInfoParcelable to a RouteInfo
+ */
+ public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+ if (routeInfo == null) {
+ return null;
+ }
+ final RouteInfoParcelable parcel = new RouteInfoParcelable();
+ parcel.destination = toStableParcelable(routeInfo.getDestination());
+ parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+ parcel.ifaceName = routeInfo.getInterface();
+ parcel.type = routeInfo.getType();
+ return parcel;
+ }
+
+ /**
+ * Convert a RouteInfo to a RouteInfoParcelable
+ */
+ public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final IpPrefix destination = fromStableParcelable(parcel.destination);
+ return new RouteInfo(
+ destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+ parcel.ifaceName, parcel.type);
+ }
+
+ /**
+ * Convert a LinkAddressParcelable to a LinkAddress
+ */
+ public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+ if (la == null) {
+ return null;
+ }
+ final LinkAddressParcelable parcel = new LinkAddressParcelable();
+ parcel.address = la.getAddress().getHostAddress();
+ parcel.prefixLength = la.getPrefixLength();
+ parcel.flags = la.getFlags();
+ parcel.scope = la.getScope();
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkAddress to a LinkAddressParcelable
+ */
+ public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new LinkAddress(
+ InetAddresses.parseNumericAddress(parcel.address),
+ parcel.prefixLength,
+ parcel.flags,
+ parcel.scope);
+ }
+
+ /**
+ * Convert a LinkProperties to a LinkPropertiesParcelable
+ */
+ public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+ if (lp == null) {
+ return null;
+ }
+ final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+ parcel.ifaceName = lp.getInterfaceName();
+ parcel.linkAddresses = toParcelableArray(
+ lp.getLinkAddresses(),
+ LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkAddressParcelable.class);
+ parcel.dnses = toParcelableArray(
+ lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.pcscfs = toParcelableArray(
+ lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+ parcel.validatedPrivateDnses = toParcelableArray(
+ lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.usePrivateDns = lp.isPrivateDnsActive();
+ parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+ parcel.domains = lp.getDomains();
+ parcel.routes = toParcelableArray(
+ lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+ RouteInfoParcelable.class);
+ parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+ parcel.mtu = lp.getMtu();
+ parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+ parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+ parcel.stackedLinks = toParcelableArray(
+ lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkPropertiesParcelable.class);
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkPropertiesParcelable to a LinkProperties
+ */
+ public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(parcel.ifaceName);
+ lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+ LinkPropertiesParcelableUtil::fromStableParcelable));
+ lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+ lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+ lp.setValidatedPrivateDnsServers(
+ fromParcelableArray(parcel.validatedPrivateDnses,
+ InetAddresses::parseNumericAddress));
+ lp.setUsePrivateDns(parcel.usePrivateDns);
+ lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+ lp.setDomains(parcel.domains);
+ for (RouteInfoParcelable route : parcel.routes) {
+ lp.addRoute(fromStableParcelable(route));
+ }
+ lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+ lp.setMtu(parcel.mtu);
+ lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+ lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+ for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+ lp.addStackedLink(fromStableParcelable(stackedLink));
+ }
+ return lp;
+ }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 000000000000..a18976c9eee6
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package android.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+ // Below methods could be implemented easily with streams, but streams are frowned upon in
+ // frameworks code.
+
+ /**
+ * Convert a list of BaseType items to an array of ParcelableType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+ @NonNull List<BaseType> base,
+ @NonNull Function<BaseType, ParcelableType> conv,
+ @NonNull Class<ParcelableType> parcelClass) {
+ final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+ int i = 0;
+ for (BaseType b : base) {
+ out[i] = conv.apply(b);
+ i++;
+ }
+ return out;
+ }
+
+ /**
+ * Convert an array of ParcelableType items to a list of BaseType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+ @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+ final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+ for (ParcelableType t : parceled) {
+ out.add(conv.apply(t));
+ }
+ return out;
+ }
+}
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0bf3136..329911776993 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.Intent;
@@ -27,8 +28,8 @@ import android.os.Message;
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
/**
* This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@ public abstract class CallRedirectionService extends Service {
/**
* Telecom calls this method to inform the implemented {@link CallRedirectionService} of
- * a new outgoing call which is being placed.
+ * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+ * calls and does not request to redirect calls with gateway information.
+ *
+ * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+ * the implemented {@link CallRedirectionService} set by users.
*
- * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
- * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+ * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+ * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+ * from here.
*
- * @param handle the phone number dialed by the user
- * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param handle the phone number dialed by the user, represented in E.164 format if possible
+ * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users. Will be {@code false} if, for example
+ * the device is in car mode and the user would not be able to
+ * interact with their device.
*/
- public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+ public abstract void onPlaceCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse);
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
- * are required to the outgoing call, and that the call should be placed as-is.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * no changes are required to the outgoing call, and that the call should be placed as-is.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@ public abstract class CallRedirectionService extends Service {
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
- * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+ * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+ * replies Telecom a handle for an emergency number.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
* If {@code null}, no change will be made to the
* {@link PhoneAccountHandle} used to place the call.
+ * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+ * if the confirmFirst is true, and if the redirection request of this
+ * response was sent with a true flag of allowInteractiveResponse via
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
*/
- public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+ public final void redirectCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst) {
try {
- mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+ mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
} catch (RemoteException e) {
}
}
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
- * call should be canceled entirely.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * an outgoing call should be canceled entirely.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void cancelCall() {
@@ -137,7 +161,8 @@ public abstract class CallRedirectionService extends Service {
SomeArgs args = (SomeArgs) msg.obj;
try {
mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
- onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+ onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+ (boolean) args.arg4);
} finally {
args.recycle();
}
@@ -152,15 +177,20 @@ public abstract class CallRedirectionService extends Service {
* Telecom calls this method to inform the CallRedirectionService of a new outgoing call
* which is about to be placed.
* @param handle the phone number dialed by the user
- * @param targetPhoneAccount the URI of the number the user dialed
+ * @param initialPhoneAccount the URI of the number the user dialed
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users.
*/
@Override
- public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
- PhoneAccountHandle targetPhoneAccount) {
+ public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = adapter;
args.arg2 = handle;
- args.arg3 = targetPhoneAccount;
+ args.arg3 = initialPhoneAccount;
+ args.arg4 = allowInteractiveResponse;
mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983f52a2..0a42a3f4f02e 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@ oneway interface ICallRedirectionAdapter {
void placeCallUnmodified();
- void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+ void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst);
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360beb64d..c1bc44007b0b 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@ import com.android.internal.telecom.ICallRedirectionAdapter;
*/
oneway interface ICallRedirectionService {
void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
- in PhoneAccountHandle targetPhoneAccount);
+ in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
}
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index fe07370394ad..4da79b34a55e 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -110,6 +110,7 @@ public final class AvailableNetworkInfo implements Parcelable {
private AvailableNetworkInfo(Parcel in) {
mSubId = in.readInt();
mPriority = in.readInt();
+ mMccMncs = new ArrayList<>();
in.readStringList(mMccMncs);
}
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f04c5ae..eafbfbc5076d 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@ public class CellConfigLte implements Parcelable {
}
/** @hide */
+ public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+ mIsEndcAvailable = cellConfig.isEndcAvailable;
+ }
+
+ /** @hide */
public CellConfigLte(boolean isEndcAvailable) {
mIsEndcAvailable = isEndcAvailable;
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7bf70c..8ce5c54c810e 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
@@ -318,6 +320,13 @@ public abstract class CellInfo implements Parcelable {
}
/** @hide */
+ protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+ this.mRegistered = ci.isRegistered;
+ this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+ this.mCellConnectionStatus = ci.connectionStatus;
+ }
+
+ /** @hide */
public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
if (ci == null) return null;
switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@ public abstract class CellInfo implements Parcelable {
default: return null;
}
}
+
+ /** @hide */
+ public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+ if (ci == null) return null;
+ switch (ci.info.getDiscriminator()) {
+ case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+ case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+ case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+ case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+ case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+ default: return null;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07dab6bbd..4440108879f2 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@ public final class CellInfoCdma extends CellInfo implements Parcelable {
new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
}
+ /** @hide */
+ public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+ mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+ mCellSignalStrengthCdma =
+ new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ }
+
@Override
public CellIdentityCdma getCellIdentity() {
return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfae7295..248adfcb2d90 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@ public final class CellInfoGsm extends CellInfo implements Parcelable {
mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
}
+ /** @hide */
+ public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+ mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+ mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ }
+
@Override
public CellIdentityGsm getCellIdentity() {
return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 75938317bf44..8e8ce8a1f5de 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@ public final class CellInfoLte extends CellInfo implements Parcelable {
mCellConfig = new CellConfigLte();
}
+ /** @hide */
+ public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+ mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+ mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+ mCellConfig = new CellConfigLte(cil.cellConfig);
+ }
+
@Override
public CellIdentityLte getCellIdentity() {
if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7bf68e..2ab38fb77a90 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@ public final class CellInfoTdscdma extends CellInfo implements Parcelable {
mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
}
+ /** @hide */
+ public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+ mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+ mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ }
+
@Override public CellIdentityTdscdma getCellIdentity() {
return mCellIdentityTdscdma;
}
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80fd65c..65e047077639 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@ public final class CellInfoWcdma extends CellInfo implements Parcelable {
mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
}
+ /** @hide */
+ public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+ mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+ mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ }
+
@Override
public CellIdentityWcdma getCellIdentity() {
return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 430d24fd812b..71b18fd4ca84 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9796,7 +9796,7 @@ public class TelephonyManager {
boolean ret = false;
try {
IOns iOpportunisticNetworkService = getIOns();
- if (iOpportunisticNetworkService != null) {
+ if (iOpportunisticNetworkService != null && availableNetworks != null) {
ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
pkgForDebug);
}
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index fe062d5d974a..a94b163ffd75 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -29,6 +29,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -198,21 +199,53 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
}
+ /**
+ * Indicated the framework does not know whether an emergency call should be placed using
+ * emergency or normal call routing. This means the underlying radio or IMS implementation is
+ * free to determine for itself how to route the call.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0;
+ /**
+ * Indicates the radio or IMS implementation must handle the call through emergency routing.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1;
+ /**
+ * Indicates the radio or IMS implementation must handle the call through normal call routing.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2;
+
+ /**
+ * The routing to tell how to handle the call for the corresponding emergency number.
+ *
+ * @hide
+ */
+ @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = {
+ EMERGENCY_CALL_ROUTING_UNKNOWN,
+ EMERGENCY_CALL_ROUTING_EMERGENCY,
+ EMERGENCY_CALL_ROUTING_NORMAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EmergencyCallRouting {}
+
+
private final String mNumber;
private final String mCountryIso;
private final String mMnc;
private final int mEmergencyServiceCategoryBitmask;
private final int mEmergencyNumberSourceBitmask;
+ private final int mEmergencyCallRouting;
/** @hide */
- public EmergencyNumber(@NonNull String number, @NonNull String countryIso,
- @NonNull String mnc, int emergencyServiceCategories,
- int emergencyNumberSources) {
+ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
+ @EmergencyServiceCategories int emergencyServiceCategories,
+ @EmergencyNumberSources int emergencyNumberSources,
+ @EmergencyCallRouting int emergencyCallRouting) {
this.mNumber = number;
this.mCountryIso = countryIso;
this.mMnc = mnc;
this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
+ this.mEmergencyCallRouting = emergencyCallRouting;
}
/** @hide */
@@ -222,8 +255,33 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
mMnc = source.readString();
mEmergencyServiceCategoryBitmask = source.readInt();
mEmergencyNumberSourceBitmask = source.readInt();
+ mEmergencyCallRouting = source.readInt();
+ }
+
+ @Override
+ /** @hide */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mNumber);
+ dest.writeString(mCountryIso);
+ dest.writeString(mMnc);
+ dest.writeInt(mEmergencyServiceCategoryBitmask);
+ dest.writeInt(mEmergencyNumberSourceBitmask);
+ dest.writeInt(mEmergencyCallRouting);
}
+ public static final Parcelable.Creator<EmergencyNumber> CREATOR =
+ new Parcelable.Creator<EmergencyNumber>() {
+ @Override
+ public EmergencyNumber createFromParcel(Parcel in) {
+ return new EmergencyNumber(in);
+ }
+
+ @Override
+ public EmergencyNumber[] newArray(int size) {
+ return new EmergencyNumber[size];
+ }
+ };
+
/**
* Get the dialing number of the emergency number.
*
@@ -352,14 +410,17 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
return (mEmergencyNumberSourceBitmask & sources) == sources;
}
- @Override
- /** @hide */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mNumber);
- dest.writeString(mCountryIso);
- dest.writeString(mMnc);
- dest.writeInt(mEmergencyServiceCategoryBitmask);
- dest.writeInt(mEmergencyNumberSourceBitmask);
+ /**
+ * Returns the emergency call routing information.
+ *
+ * <p>Some regions require some emergency numbers which are not routed using typical emergency
+ * call processing, but are instead placed as regular phone calls. The emergency call routing
+ * field provides information about how an emergency call will be routed when it is placed.
+ *
+ * @return the emergency call routing requirement
+ */
+ public @EmergencyCallRouting int getEmergencyCallRouting() {
+ return mEmergencyCallRouting;
}
@Override
@@ -373,7 +434,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
+ "|Mnc-" + mMnc
+ "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
- + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+ + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
+ + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
}
@Override
@@ -381,7 +443,19 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
if (!EmergencyNumber.class.isInstance(o)) {
return false;
}
- return (o == this || toString().equals(o.toString()));
+ EmergencyNumber other = (EmergencyNumber) o;
+ return mNumber.equals(other.mNumber)
+ && mCountryIso.equals(other.mCountryIso)
+ && mMnc.equals(other.mMnc)
+ && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
+ && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
+ && mEmergencyCallRouting == other.mEmergencyCallRouting;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
+ mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
}
/**
@@ -462,12 +536,12 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
continue;
}
for (int j = i + 1; j < emergencyNumberList.size(); j++) {
- if (isSameEmergencyNumber(
+ if (areSameEmergencyNumbers(
emergencyNumberList.get(i), emergencyNumberList.get(j))) {
Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
+ emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j));
// Set the merged emergency number in the current position
- emergencyNumberList.set(i, mergeNumbers(
+ emergencyNumberList.set(i, mergeSameEmergencyNumbers(
emergencyNumberList.get(i), emergencyNumberList.get(j)));
// Mark the emergency number has been merged
mergedEmergencyNumber.add(emergencyNumberList.get(j));
@@ -486,8 +560,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
* Check if two emergency numbers are the same.
*
* A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
- * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
- * for the same EmergencyNumber.
+ * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be
+ * merged into one bitfield for the same EmergencyNumber.
*
* @param first first EmergencyNumber to compare
* @param second second EmergencyNumber to compare
@@ -495,8 +569,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
*
* @hide
*/
- public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first,
- @NonNull EmergencyNumber second) {
+ public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
if (!first.getNumber().equals(second.getNumber())) {
return false;
}
@@ -510,11 +584,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
!= second.getEmergencyServiceCategoryBitmask()) {
return false;
}
+ if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
+ return false;
+ }
return true;
}
/**
- * Get a merged EmergencyNumber for two numbers if they are the same.
+ * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are
+ * the same if {@link #areSameEmergencyNumbers} returns {@code true}.
*
* @param first first EmergencyNumber to compare
* @param second second EmergencyNumber to compare
@@ -522,27 +600,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu
*
* @hide
*/
- public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first,
- @NonNull EmergencyNumber second) {
- if (isSameEmergencyNumber(first, second)) {
+ public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
+ if (areSameEmergencyNumbers(first, second)) {
return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
first.getEmergencyServiceCategoryBitmask(),
first.getEmergencyNumberSourceBitmask()
- | second.getEmergencyNumberSourceBitmask());
+ | second.getEmergencyNumberSourceBitmask(),
+ first.getEmergencyCallRouting());
}
return null;
}
-
- public static final Parcelable.Creator<EmergencyNumber> CREATOR =
- new Parcelable.Creator<EmergencyNumber>() {
- @Override
- public EmergencyNumber createFromParcel(Parcel in) {
- return new EmergencyNumber(in);
- }
-
- @Override
- public EmergencyNumber[] newArray(int size) {
- return new EmergencyNumber[size];
- }
- };
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index cb6fcd7b62c2..9c8d078a579b 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -24,9 +24,11 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.VideoProfile;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
import java.lang.annotation.Retention;
@@ -321,6 +323,20 @@ public final class ImsCallProfile implements Parcelable {
EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
/**
+ * The emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ private @EmergencyCallRouting int mEmergencyCallRouting =
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+
+ /**
* Extras associated with this {@link ImsCallProfile}.
* <p>
* Valid data types include:
@@ -503,10 +519,12 @@ public final class ImsCallProfile implements Parcelable {
@Override
public String toString() {
- return "{ serviceType=" + mServiceType +
- ", callType=" + mCallType +
- ", restrictCause=" + mRestrictCause +
- ", mediaProfile=" + mMediaProfile.toString() + " }";
+ return "{ serviceType=" + mServiceType
+ + ", callType=" + mCallType
+ + ", restrictCause=" + mRestrictCause
+ + ", mediaProfile=" + mMediaProfile.toString()
+ + ", emergencyServiceCategories=" + mEmergencyCallRouting
+ + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
}
@Override
@@ -522,6 +540,7 @@ public final class ImsCallProfile implements Parcelable {
out.writeBundle(filteredExtras);
out.writeParcelable(mMediaProfile, 0);
out.writeInt(mEmergencyServiceCategories);
+ out.writeInt(mEmergencyCallRouting);
}
private void readFromParcel(Parcel in) {
@@ -530,6 +549,7 @@ public final class ImsCallProfile implements Parcelable {
mCallExtras = in.readBundle();
mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
mEmergencyServiceCategories = in.readInt();
+ mEmergencyCallRouting = in.readInt();
}
public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -740,6 +760,21 @@ public final class ImsCallProfile implements Parcelable {
}
/**
+ * Set the emergency service categories and emergency call routing. The set value is valid
+ * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * Reference: 3gpp 23.167, Section 6 - Functional description;
+ * 3gpp 22.101, Section 10 - Emergency Calls.
+ *
+ * @hide
+ */
+ public void setEmergencyCallInfo(EmergencyNumber num) {
+ setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+ setEmergencyCallRouting(num.getEmergencyCallRouting());
+ }
+
+
+ /**
* Set the emergency service categories. The set value is valid only if
* {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -758,12 +793,29 @@ public final class ImsCallProfile implements Parcelable {
* Reference: 3gpp 23.167, Section 6 - Functional description;
* 3gpp 22.101, Section 10 - Emergency Calls.
*/
+ @VisibleForTesting
public void setEmergencyServiceCategories(
@EmergencyServiceCategories int emergencyServiceCategories) {
mEmergencyServiceCategories = emergencyServiceCategories;
}
/**
+ * Set the emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ @VisibleForTesting
+ public void setEmergencyCallRouting(@EmergencyCallRouting int emergencyCallRouting) {
+ mEmergencyCallRouting = emergencyCallRouting;
+ }
+
+ /**
* Get the emergency service categories, only valid if {@link #getServiceType} returns
* {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -787,4 +839,19 @@ public final class ImsCallProfile implements Parcelable {
public @EmergencyServiceCategories int getEmergencyServiceCategories() {
return mEmergencyServiceCategories;
}
+
+ /**
+ * Get the emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ public @EmergencyCallRouting int getEmergencyCallRouting() {
+ return mEmergencyCallRouting;
+ }
}
diff --git a/test-base/api/current.txt b/test-base/api/current.txt
index 7ebd6aa8a4a2..91fcca5cac25 100644
--- a/test-base/api/current.txt
+++ b/test-base/api/current.txt
@@ -48,6 +48,9 @@ package android.test {
method public abstract void startTiming(boolean);
}
+ public abstract deprecated class RepetitiveTest implements java.lang.annotation.Annotation {
+ }
+
public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
}
diff --git a/test-base/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
index 6a7130e68e61..13e89d2d92a6 100644
--- a/test-base/src/android/test/RepetitiveTest.java
+++ b/test-base/src/android/test/RepetitiveTest.java
@@ -26,8 +26,10 @@ import java.lang.annotation.Target;
* When the annotation is present, the test method is executed the number of times specified by
* numIterations and defaults to 1.
*
- * {@hide} Not needed for public API.
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepetitiveTest {
@@ -37,4 +39,4 @@ public @interface RepetitiveTest {
* @return The total number of iterations, the default is 1.
*/
int numIterations() default 1;
-} \ No newline at end of file
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714f07b0..a69f422b3bdb 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@ java_library_static {
static_libs: [
"android.test.base-minus-junit",
"android.test.runner-minus-junit",
- "android.test.mock.impl",
+ "android.test.mock_static",
],
no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index e1d6e01d6d06..43b765d8b783 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,3 +30,19 @@ java_sdk_library {
srcs_lib_whitelist_pkgs: ["android"],
compile_dex: true,
}
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+ name: "android.test.mock_static",
+
+ java_version: "1.8",
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+}
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 932fee0c1956..299fbefc78e4 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -849,6 +849,18 @@ public class LinkPropertiesTest {
assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
}
+ private void assertParcelingIsLossless(LinkProperties source) {
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalled = p.marshall();
+ p = Parcel.obtain();
+ p.unmarshall(marshalled, 0, marshalled.length);
+ p.setDataPosition(0);
+ LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+ assertEquals(source, dest);
+ }
+
@Test
public void testLinkPropertiesParcelable() throws Exception {
LinkProperties source = new LinkProperties();
@@ -870,15 +882,12 @@ public class LinkPropertiesTest {
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- Parcel p = Parcel.obtain();
- source.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- final byte[] marshalled = p.marshall();
- p = Parcel.obtain();
- p.unmarshall(marshalled, 0, marshalled.length);
- p.setDataPosition(0);
- LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+ assertParcelingIsLossless(source);
+ }
- assertEquals(source, dest);
+ @Test
+ public void testParcelUninitialized() throws Exception {
+ LinkProperties empty = new LinkProperties();
+ assertParcelingIsLossless(empty);
}
}
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 000000000000..4cabfc95b49d
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+ private LinkProperties mLinkProperties;
+
+ private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+ private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+ private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+ @Before
+ public void setUp() {
+ mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+ }
+
+ private static LinkProperties makeLinkProperties(String iface) {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(iface);
+ lp.setLinkAddresses(Arrays.asList(
+ new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+ lp.setDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::42"),
+ InetAddresses.parseNumericAddress("192.168.1.1")
+ ));
+ lp.setValidatedPrivateDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::43"),
+ InetAddresses.parseNumericAddress("192.168.42.43")
+ ));
+ lp.setPcscfServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::47"),
+ InetAddresses.parseNumericAddress("192.168.42.47")
+ ));
+ lp.setUsePrivateDns(true);
+ lp.setPrivateDnsServerName("test.example.com");
+ lp.setDomains("test1.example.com,test2.example.com");
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+ InetAddresses.parseNumericAddress("2001:db8::45"),
+ iface,
+ RouteInfo.RTN_UNICAST
+ ));
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+ InetAddresses.parseNumericAddress("192.168.45.1"),
+ iface,
+ RouteInfo.RTN_THROW
+ ));
+ lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+ "excl1.example.com,excl2.example.com"));
+ lp.setMtu(5000);
+ lp.setTcpBufferSizes("1,2,3,4,5,6");
+ lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+ // Verify that this test does not miss any new field added later.
+ // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+ // must also be updated.
+ assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+ .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+ return lp;
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullInterface() {
+ mLinkProperties.setInterfaceName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullPrivateDnsServer() {
+ mLinkProperties.setPrivateDnsServerName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullDomains() {
+ mLinkProperties.setDomains(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullProxy() {
+ mLinkProperties.setHttpProxy(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullTcpBufferSizes() {
+ mLinkProperties.setTcpBufferSizes(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyLinkAddresses() {
+ mLinkProperties.setLinkAddresses(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyDnses() {
+ mLinkProperties.setDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+ mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyRoutes() {
+ for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+ mLinkProperties.removeRoute(r);
+ }
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_PacFileProxyInfo() {
+ mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullNat64Prefix() {
+ mLinkProperties.setNat64Prefix(null);
+ doParcelUnparcelTest();
+ }
+
+ private void doParcelUnparcelTest() {
+ final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+ assertLinkPropertiesEquals(mLinkProperties, unparceled);
+ }
+
+ private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+ assertEquals(expected, actual);
+
+ // LinkProperties equals() does not include stacked links
+ assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bf3964416e11..2a92a7dabd98 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4683,7 +4683,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+ verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME);
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
// Clat iface up, expect stack link updated.
@@ -4710,7 +4710,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+ verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
// Clat iface removed, expect linkproperties revert to original one
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4c52d818269d..9578ded1a089 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,11 +32,13 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.net.NetworkStack;
+import android.os.INetworkManagementService;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.format.DateUtils;
@@ -66,6 +68,8 @@ public class LingerMonitorTest {
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
+ @Mock INetd mNetd;
+ @Mock INetworkManagementService mNMS;
@Mock Context mCtx;
@Mock NetworkMisc mMisc;
@Mock NetworkNotificationManager mNotifier;
@@ -352,7 +356,7 @@ public class LingerMonitorTest {
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService);
+ caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
nai.everValidated = true;
return nai;
}
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index bf42412d68d8..07b1d057c882 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -17,9 +17,7 @@
package com.android.server.connectivity;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -27,6 +25,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -57,6 +56,7 @@ public class Nat464XlatTest {
@Mock ConnectivityService mConnectivity;
@Mock NetworkMisc mMisc;
+ @Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@Mock InterfaceConfiguration mConfig;
@Mock NetworkAgentInfo mNai;
@@ -65,7 +65,7 @@ public class Nat464XlatTest {
Handler mHandler;
Nat464Xlat makeNat464Xlat() {
- return new Nat464Xlat(mNms, mNai);
+ return new Nat464Xlat(mNai, mNetd, mNms);
}
@Before
@@ -129,7 +129,7 @@ public class Nat464XlatTest {
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -144,7 +144,7 @@ public class Nat464XlatTest {
// ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
nat.stop();
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
// Stacked interface removed notification arrives.
nat.interfaceRemoved(STACKED_IFACE);
@@ -156,7 +156,7 @@ public class Nat464XlatTest {
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -168,7 +168,7 @@ public class Nat464XlatTest {
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -185,7 +185,7 @@ public class Nat464XlatTest {
mLooper.dispatchNext();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
assertTrue(c.getValue().getStackedLinks().isEmpty());
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -194,7 +194,7 @@ public class Nat464XlatTest {
// ConnectivityService stops clat: no-op.
nat.stop();
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -205,13 +205,13 @@ public class Nat464XlatTest {
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
assertIdle(nat);
// In-flight interface up notification arrives: no-op
@@ -225,7 +225,7 @@ public class Nat464XlatTest {
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -236,16 +236,16 @@ public class Nat464XlatTest {
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
static void assertIdle(Nat464Xlat nat) {
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
index 859a54d29321..e63c3b02d1c3 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server.net.ipmemorystore;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+
import android.content.Context;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -26,6 +29,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.File;
+
/** Unit tests for {@link IpMemoryStoreServiceTest}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -36,6 +41,7 @@ public class IpMemoryStoreServiceTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ doReturn(new File("/tmp/test.db")).when(mMockContext).getDatabasePath(anyString());
}
@Test
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
new file mode 100644
index 000000000000..8d367e2fc387
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package com.android.server.net.ipmemorystore;
+
+import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link RelevanceUtils}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelevanceUtilsTests {
+ @Test
+ public void testComputeRelevanceForTargetDate() {
+ final long dayInMillis = 24L * 60 * 60 * 1000;
+ final long base = 1_000_000L; // any given point in time
+ // Relevance when the network expires in 1000 years must be capped
+ assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
+ base + 1000L * dayInMillis, base));
+ // Relevance when expiry is before the date must be 0
+ assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
+ // Make sure the relevance for a given target date is higher if the expiry is further
+ // in the future
+ assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
+ < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
+
+ // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
+ // the decay is indeed logarithmic.
+ final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
+ final int relevance50DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
+ final int relevance100DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
+ final int relevance150DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
+ assertEquals(0, relevanceAtExpiry);
+ assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
+ < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
+ assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
+ < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
+ }
+
+ @Test
+ public void testIncreaseRelevance() {
+ long expiry = System.currentTimeMillis();
+
+ final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
+ // Though a few milliseconds might have elapsed, the first bump should push the duration
+ // to days in the future, so unless this test takes literal days between these two lines,
+ // this should always pass.
+ assertTrue(firstBump > expiry);
+
+ expiry = 0;
+ long lastDifference = Long.MAX_VALUE;
+ // The relevance should be capped in at most this many steps. Otherwise, fail.
+ final int steps = 1000;
+ for (int i = 0; i < steps; ++i) {
+ final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
+ if (newExpiry == expiry) {
+ // The relevance should be capped. Make sure it is, then exit without failure.
+ assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+ return;
+ }
+ // Make sure the new expiry is further in the future than last time.
+ assertTrue(newExpiry > expiry);
+ // Also check that it was not bumped as much as the last bump, because the
+ // decay must be exponential.
+ assertTrue(newExpiry - expiry < lastDifference);
+ lastDifference = newExpiry - expiry;
+ expiry = newExpiry;
+ }
+ fail("Relevance failed to go to the maximum value after " + steps + " bumps");
+ }
+
+ @Test
+ public void testContinuity() {
+ final long expiry = System.currentTimeMillis();
+
+ // Relevance at expiry and after expiry should be the cap.
+ final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
+ assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
+ final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+ assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
+
+ // If the max relevance is reached at the cap lifetime, one millisecond less than this
+ // should be very close. Strictly speaking this is a bit brittle, but it should be
+ // good enough for the purposes of the memory store.
+ final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
+ expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
+ assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
+ assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
+
+ // Likewise the relevance one millisecond before expiry should be very close to 0. It's
+ // fine if it rounds down to 0.
+ final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
+ expiry, expiry - 1);
+ assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
+ assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
+
+ final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
+ assertEquals(relevanceAtExpiry, 0);
+ final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry + 1_000_000);
+ assertEquals(relevanceAfterExpiry, 0);
+ }
+
+ // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
+ // monotonically increasing date as a side effect, but this tests that the relevance (as
+ // opposed to the expiry date) increases monotonically with increasing periods.
+ @Test
+ public void testMonotonicity() {
+ // Hopefully the relevance is granular enough to give a different value for every one
+ // of this number of steps.
+ final int steps = 40;
+ final long expiry = System.currentTimeMillis();
+
+ int lastRelevance = -1;
+ for (int i = 0; i < steps; ++i) {
+ final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
+ final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
+ assertTrue(relevance > lastRelevance);
+ lastRelevance = relevance;
+ }
+ }
+}