summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt12
-rw-r--r--api/system-current.txt12
-rw-r--r--api/test-current.txt12
-rw-r--r--core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl2
-rw-r--r--core/java/android/database/ContentObserver.java10
-rw-r--r--core/java/android/net/LinkAddress.java20
-rw-r--r--core/java/android/net/metrics/IpManagerEvent.java3
-rw-r--r--core/java/android/os/Debug.java71
-rw-r--r--core/java/android/os/HwBinder.java5
-rw-r--r--core/jni/android_os_Debug.cpp56
-rw-r--r--core/jni/android_os_HwBinder.cpp17
-rw-r--r--core/jni/android_text_AndroidBidi.cpp2
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--services/core/java/com/android/server/IpSecService.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java42
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java80
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java95
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java55
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java2
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java5
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java58
-rw-r--r--services/core/java/com/android/server/timezone/PackageTracker.java40
-rw-r--r--services/net/java/android/net/ip/IpManager.java141
-rw-r--r--services/net/java/android/net/util/NetworkConstants.java1
-rw-r--r--services/net/java/android/net/util/PrefixUtils.java74
-rw-r--r--telephony/java/android/telephony/MbmsDownloadManager.java147
-rw-r--r--telephony/java/android/telephony/MbmsStreamingManager.java44
-rwxr-xr-xtelephony/java/android/telephony/mbms/DownloadStatus.aidl19
-rw-r--r--telephony/java/android/telephony/mbms/DownloadStatus.java77
-rwxr-xr-xtelephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl2
-rw-r--r--telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java2
-rw-r--r--telephony/java/android/telephony/mbms/MbmsException.java125
-rw-r--r--telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java15
-rw-r--r--telephony/java/android/telephony/mbms/MbmsUtils.java5
-rw-r--r--telephony/java/android/telephony/mbms/StreamingService.java53
-rwxr-xr-xtelephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl12
-rwxr-xr-xtelephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl3
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java74
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java17
-rw-r--r--tests/net/java/android/net/ip/IpManagerTest.java178
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java89
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java50
43 files changed, 1293 insertions, 445 deletions
diff --git a/Android.mk b/Android.mk
index 5f759cbd843c..aec1bde15439 100644
--- a/Android.mk
+++ b/Android.mk
@@ -550,7 +550,6 @@ include $(CLEAR_VARS)
aidl_files := \
frameworks/base/telephony/java/android/telephony/mbms/DownloadRequest.aidl \
- frameworks/base/telephony/java/android/telephony/mbms/DownloadStatus.aidl \
frameworks/base/telephony/java/android/telephony/mbms/FileInfo.aidl \
frameworks/base/telephony/java/android/telephony/mbms/FileServiceInfo.aidl \
frameworks/base/telephony/java/android/telephony/mbms/ServiceInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 1deb3adbeecb..40fd30837fbb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -114,6 +114,7 @@ package android {
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -36684,14 +36685,18 @@ package android.system {
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -36714,6 +36719,13 @@ package android.system {
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
diff --git a/api/system-current.txt b/api/system-current.txt
index 48d2aba3cd21..13e283c46761 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -206,6 +206,7 @@ package android {
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
+ field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -39635,14 +39636,18 @@ package android.system {
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -39665,6 +39670,13 @@ package android.system {
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
diff --git a/api/test-current.txt b/api/test-current.txt
index 5dab3d11f306..9d23dc83ec66 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -114,6 +114,7 @@ package android {
field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ field public static final java.lang.String SEND_EMBMS_INTENTS = "android.permission.SEND_EMBMS_INTENTS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
@@ -36767,14 +36768,18 @@ package android.system {
public final class StructStat {
ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+ ctor public StructStat(long, long, int, long, int, int, long, long, android.system.StructTimespec, android.system.StructTimespec, android.system.StructTimespec, long, long);
+ field public final android.system.StructTimespec st_atim;
field public final long st_atime;
field public final long st_blksize;
field public final long st_blocks;
+ field public final android.system.StructTimespec st_ctim;
field public final long st_ctime;
field public final long st_dev;
field public final int st_gid;
field public final long st_ino;
field public final int st_mode;
+ field public final android.system.StructTimespec st_mtim;
field public final long st_mtime;
field public final long st_nlink;
field public final long st_rdev;
@@ -36797,6 +36802,13 @@ package android.system {
field public final long f_namemax;
}
+ public final class StructTimespec implements java.lang.Comparable {
+ ctor public StructTimespec(long, long);
+ method public int compareTo(android.system.StructTimespec);
+ field public final long tv_nsec;
+ field public final long tv_sec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public final java.lang.String machine;
diff --git a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
index feccdce57b98..0da4e8843282 100644
--- a/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl
@@ -21,7 +21,7 @@ package android.bluetooth;
*
* {@hide}
*/
-interface IBluetoothStateChangeCallback
+oneway interface IBluetoothStateChangeCallback
{
void onBluetoothStateChange(boolean on);
}
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index 4795e979f644..5f01e300bf42 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -193,11 +193,6 @@ public abstract class ContentObserver {
*/
private void dispatchChange(boolean selfChange, Uri uri, int userId) {
if (mHandler == null) {
- synchronized (mLock) {
- if (mTransport == null) {
- return;
- }
- }
onChange(selfChange, uri, userId);
} else {
mHandler.post(new NotificationRunnable(selfChange, uri, userId));
@@ -218,11 +213,6 @@ public abstract class ContentObserver {
@Override
public void run() {
- synchronized (mLock) {
- if (mTransport == null) {
- return;
- }
- }
ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
}
}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 6e74f14bd138..62de9911bc48 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -16,6 +16,15 @@
package android.net;
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
@@ -26,15 +35,6 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
-
/**
* Identifies an IP address on a network link.
*
@@ -101,7 +101,7 @@ public class LinkAddress implements Parcelable {
* Per RFC 4193 section 8, fc00::/7 identifies these addresses.
*/
private boolean isIPv6ULA() {
- if (address != null && address instanceof Inet6Address) {
+ if (address instanceof Inet6Address) {
byte[] bytes = address.getAddress();
return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
}
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index e0a026ed678d..007846e8c1ae 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -42,10 +42,13 @@ public final class IpManagerEvent implements Parcelable {
/** @hide */ public static final int ERROR_STARTING_IPV6 = 5;
/** @hide */ public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6;
+ /** @hide */ public static final int ERROR_INVALID_PROVISIONING = 7;
+
/** {@hide} */
@IntDef(value = {
PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
+ ERROR_INVALID_PROVISIONING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index e05bd89079af..55b6dc817e5c 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -221,28 +221,69 @@ public final class Debug
/** @hide */
public static final int OTHER_OTHER_MEMTRACK = 16;
+ // Needs to be declared here for the DVK_STAT ranges below.
+ /** @hide */
+ public static final int NUM_OTHER_STATS = 17;
+
+ // Dalvik subsections.
/** @hide */
public static final int OTHER_DALVIK_NORMAL = 17;
/** @hide */
public static final int OTHER_DALVIK_LARGE = 18;
/** @hide */
- public static final int OTHER_DALVIK_LINEARALLOC = 19;
+ public static final int OTHER_DALVIK_ZYGOTE = 19;
+ /** @hide */
+ public static final int OTHER_DALVIK_NON_MOVING = 20;
+ // Section begins and ends for dumpsys, relative to the DALVIK categories.
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DALVIK_START =
+ OTHER_DALVIK_NORMAL - NUM_OTHER_STATS;
/** @hide */
- public static final int OTHER_DALVIK_ACCOUNTING = 20;
+ public static final int OTHER_DVK_STAT_DALVIK_END =
+ OTHER_DALVIK_NON_MOVING - NUM_OTHER_STATS;
+
+ // Dalvik Other subsections.
+ /** @hide */
+ public static final int OTHER_DALVIK_OTHER_LINEARALLOC = 21;
+ /** @hide */
+ public static final int OTHER_DALVIK_OTHER_ACCOUNTING = 22;
/** @hide */
- public static final int OTHER_DALVIK_CODE_CACHE = 21;
+ public static final int OTHER_DALVIK_OTHER_CODE_CACHE = 23;
/** @hide */
- public static final int OTHER_DALVIK_ZYGOTE = 22;
+ public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 24;
/** @hide */
- public static final int OTHER_DALVIK_NON_MOVING = 23;
+ public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 25;
/** @hide */
- public static final int OTHER_DALVIK_INDIRECT_REFERENCE_TABLE = 24;
+ public static final int OTHER_DVK_STAT_DALVIK_OTHER_START =
+ OTHER_DALVIK_OTHER_LINEARALLOC - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DALVIK_OTHER_END =
+ OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE - NUM_OTHER_STATS;
+ // Dex subsections (Boot vdex, App dex, and App vdex).
/** @hide */
- public static final int NUM_OTHER_STATS = 17;
+ public static final int OTHER_DEX_BOOT_VDEX = 26;
+ /** @hide */
+ public static final int OTHER_DEX_APP_DEX = 27;
+ /** @hide */
+ public static final int OTHER_DEX_APP_VDEX = 28;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DEX_START = OTHER_DEX_BOOT_VDEX - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_DEX_END = OTHER_DEX_APP_VDEX - NUM_OTHER_STATS;
+
+ // Art subsections (App image, boot image).
+ /** @hide */
+ public static final int OTHER_ART_APP = 29;
+ /** @hide */
+ public static final int OTHER_ART_BOOT = 30;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_ART_START = OTHER_ART_APP - NUM_OTHER_STATS;
+ /** @hide */
+ public static final int OTHER_DVK_STAT_ART_END = OTHER_ART_BOOT - NUM_OTHER_STATS;
/** @hide */
- public static final int NUM_DVK_STATS = 8;
+ public static final int NUM_DVK_STATS = 14;
/** @hide */
public static final int NUM_CATEGORIES = 8;
@@ -406,12 +447,18 @@ public final class Debug
case OTHER_OTHER_MEMTRACK: return "Other mtrack";
case OTHER_DALVIK_NORMAL: return ".Heap";
case OTHER_DALVIK_LARGE: return ".LOS";
- case OTHER_DALVIK_LINEARALLOC: return ".LinearAlloc";
- case OTHER_DALVIK_ACCOUNTING: return ".GC";
- case OTHER_DALVIK_CODE_CACHE: return ".JITCache";
case OTHER_DALVIK_ZYGOTE: return ".Zygote";
case OTHER_DALVIK_NON_MOVING: return ".NonMoving";
- case OTHER_DALVIK_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
+ case OTHER_DALVIK_OTHER_LINEARALLOC: return ".LinearAlloc";
+ case OTHER_DALVIK_OTHER_ACCOUNTING: return ".GC";
+ case OTHER_DALVIK_OTHER_CODE_CACHE: return ".JITCache";
+ case OTHER_DALVIK_OTHER_COMPILER_METADATA: return ".CompilerMetadata";
+ case OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
+ case OTHER_DEX_BOOT_VDEX: return ".Boot vdex";
+ case OTHER_DEX_APP_DEX: return ".App dex";
+ case OTHER_DEX_APP_VDEX: return ".App vdex";
+ case OTHER_ART_APP: return ".App art";
+ case OTHER_ART_BOOT: return ".Boot art";
default: return "????";
}
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index b09c51c50d26..866e20c26a0c 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -51,6 +51,11 @@ public abstract class HwBinder implements IHwBinder {
String serviceName)
throws RemoteException, NoSuchElementException;
+ public static native final void configureRpcThreadpool(
+ long maxThreads, boolean callerWillJoin);
+
+ public static native final void joinRpcThreadpool();
+
// Returns address of the "freeFunction".
private static native final long native_init();
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 821d0e515d09..120962390ef3 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -75,14 +75,27 @@ enum {
HEAP_GL,
HEAP_OTHER_MEMTRACK,
+ // Dalvik extra sections (heap).
HEAP_DALVIK_NORMAL,
HEAP_DALVIK_LARGE,
- HEAP_DALVIK_LINEARALLOC,
- HEAP_DALVIK_ACCOUNTING,
- HEAP_DALVIK_CODE_CACHE,
HEAP_DALVIK_ZYGOTE,
HEAP_DALVIK_NON_MOVING,
- HEAP_DALVIK_INDIRECT_REFERENCE_TABLE,
+
+ // Dalvik other extra sections.
+ HEAP_DALVIK_OTHER_LINEARALLOC,
+ HEAP_DALVIK_OTHER_ACCOUNTING,
+ HEAP_DALVIK_OTHER_CODE_CACHE,
+ HEAP_DALVIK_OTHER_COMPILER_METADATA,
+ HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
+
+ // Boot vdex / app dex / app vdex
+ HEAP_DEX_BOOT_VDEX,
+ HEAP_DEX_APP_DEX,
+ HEAP_DEX_APP_VDEX,
+
+ // App art, boot art.
+ HEAP_ART_APP,
+ HEAP_ART_BOOT,
_NUM_HEAP,
_NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
@@ -297,15 +310,30 @@ static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
whichHeap = HEAP_TTF;
is_swappable = true;
} else if ((nameLen > 4 && strstr(name, ".dex") != NULL) ||
- (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0) ||
- (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0)) {
+ (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
whichHeap = HEAP_DEX;
+ subHeap = HEAP_DEX_APP_DEX;
+ is_swappable = true;
+ } else if (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0) {
+ whichHeap = HEAP_DEX;
+ // Handle system@framework@boot* and system/framework/boot*
+ if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
+ subHeap = HEAP_DEX_BOOT_VDEX;
+ } else {
+ subHeap = HEAP_DEX_APP_VDEX;
+ }
is_swappable = true;
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
whichHeap = HEAP_OAT;
is_swappable = true;
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
whichHeap = HEAP_ART;
+ // Handle system@framework@boot* and system/framework/boot*
+ if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
+ subHeap = HEAP_ART_BOOT;
+ } else {
+ subHeap = HEAP_ART_APP;
+ }
is_swappable = true;
} else if (strncmp(name, "/dev/", 5) == 0) {
if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
@@ -314,7 +342,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
whichHeap = HEAP_DALVIK_OTHER;
if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
- subHeap = HEAP_DALVIK_LINEARALLOC;
+ subHeap = HEAP_DALVIK_OTHER_LINEARALLOC;
} else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
(strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
// This is the regular Dalvik heap.
@@ -332,13 +360,14 @@ static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
whichHeap = HEAP_DALVIK;
subHeap = HEAP_DALVIK_ZYGOTE;
} else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
- subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE;
+ subHeap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
} else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name ||
- strstr(name, "/dev/ashmem/dalvik-data-code-cache") == name ||
- strstr(name, "/dev/ashmem/dalvik-CompilerMetadata") == name) {
- subHeap = HEAP_DALVIK_CODE_CACHE;
+ strstr(name, "/dev/ashmem/dalvik-data-code-cache") == name) {
+ subHeap = HEAP_DALVIK_OTHER_CODE_CACHE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-CompilerMetadata") == name) {
+ subHeap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
} else {
- subHeap = HEAP_DALVIK_ACCOUNTING; // Default to accounting.
+ subHeap = HEAP_DALVIK_OTHER_ACCOUNTING; // Default to accounting.
}
} else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
whichHeap = HEAP_CURSOR;
@@ -423,7 +452,8 @@ static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
stats[whichHeap].sharedClean += shared_clean;
stats[whichHeap].swappedOut += swapped_out;
stats[whichHeap].swappedOutPss += swapped_out_pss;
- if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
+ if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER ||
+ whichHeap == HEAP_DEX || whichHeap == HEAP_ART) {
stats[subHeap].pss += pss;
stats[subHeap].swappablePss += swappable_pss;
stats[subHeap].privateDirty += private_dirty;
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 4fc8e1109bc0..dc16220e7f84 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -42,6 +42,8 @@
using android::AndroidRuntime;
using android::hardware::hidl_vec;
using android::hardware::hidl_string;
+using android::hardware::IPCThreadState;
+using android::hardware::ProcessState;
template<typename T>
using Return = android::hardware::Return<T>;
@@ -393,6 +395,15 @@ static jobject JHwBinder_native_getService(
return JHwRemoteBinder::NewObject(env, service);
}
+void JHwBinder_native_configureRpcThreadpool(jlong maxThreads, jboolean callerWillJoin) {
+ CHECK(maxThreads > 0);
+ ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
+}
+
+void JHwBinder_native_joinRpcThreadpool() {
+ IPCThreadState::self()->joinThreadPool();
+}
+
static JNINativeMethod gMethods[] = {
{ "native_init", "()J", (void *)JHwBinder_native_init },
{ "native_setup", "()V", (void *)JHwBinder_native_setup },
@@ -406,6 +417,12 @@ static JNINativeMethod gMethods[] = {
{ "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
+
+ { "configureRpcThreadpool", "(JZ)V",
+ (void *)JHwBinder_native_configureRpcThreadpool },
+
+ { "joinRpcThreadpool", "()V",
+ (void *)JHwBinder_native_joinRpcThreadpool },
};
namespace android {
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 2a3f0361a9cd..3b97a5e6442e 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -38,7 +38,7 @@ static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
if (info != NULL) {
UErrorCode status = U_ZERO_ERROR;
UBiDi* bidi = ubidi_openSized(n, 0, &status);
- ubidi_setPara(bidi, chs, n, dir, NULL, &status);
+ ubidi_setPara(bidi, reinterpret_cast<const UChar*>(chs), n, dir, NULL, &status);
if (U_SUCCESS(status)) {
for (int i = 0; i < n; ++i) {
info[i] = ubidi_getLevelAt(bidi, i);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d2154168eef2..387eb1d4201d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1605,6 +1605,10 @@
<permission android:name="android.permission.RECEIVE_STK_COMMANDS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to send EMBMS download intents to apps-->
+ <permission android:name="android.permission.SEND_EMBMS_INTENTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by an ImsService to ensure that only the
system can bind to it.
<p>Protection level: signature|privileged
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index b88bbc1bdd69..2f9b8618cba6 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -206,7 +206,11 @@ public class IpSecService extends IIpSecService.Stub {
T get(int key) {
T val = mArray.get(key);
- val.checkOwnerOrSystemAndThrow();
+ // The value should never be null unless the resource doesn't exist
+ // (since we do not allow null resources to be added).
+ if (val != null) {
+ val.checkOwnerOrSystemAndThrow();
+ }
return val;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c5fc038028e2..784a7104bba4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16447,23 +16447,41 @@ public final class ActivityManagerService extends ActivityManagerNative
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
- final MemItem dalvikItem =
- new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, -2);
- if (dalvikSubitemPss.length > 0) {
- dalvikItem.subitems = new ArrayList<MemItem>();
- for (int j=0; j<dalvikSubitemPss.length; j++) {
- final String name = Debug.MemoryInfo.getOtherLabel(
- Debug.MemoryInfo.NUM_OTHER_STATS + j);
- dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
- dalvikSubitemSwapPss[j], j));
- }
- }
- catMems.add(dalvikItem);
+ final int dalvikId = -2;
+ catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId));
catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
}
+ if (dalvikSubitemPss.length > 0) {
+ // Add dalvik subitems.
+ for (MemItem memItem : catMems) {
+ int memItemStart = 0, memItemEnd = 0;
+ if (memItem.id == dalvikId) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DALVIK_OTHER) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DEX) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_ART) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_ART_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_ART_END;
+ } else {
+ continue; // No subitems, continue.
+ }
+ memItem.subitems = new ArrayList<MemItem>();
+ for (int j=memItemStart; j<=memItemEnd; j++) {
+ final String name = Debug.MemoryInfo.getOtherLabel(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+ dalvikSubitemSwapPss[j], j));
+ }
+ }
+ }
ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
for (int j=0; j<oomPss.length; j++) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index ae385c114afe..3a4e07e96ad7 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -57,6 +57,7 @@ import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.net.wifi.WifiManager;
import android.os.Binder;
@@ -213,10 +214,10 @@ public class Tethering extends BaseNetworkObserver {
mContext.getContentResolver(),
mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
- mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK );
+ mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new HashSet<>();
mSimChange = new SimChangeListener(
- mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
+ mContext, smHandler, () -> reevaluateSimCardProvisioning());
mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
@@ -224,13 +225,13 @@ public class Tethering extends BaseNetworkObserver {
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
+ mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_SHARED);
filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
filter.addDataScheme("file");
- mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
+ mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
// load device config info
updateConfiguration();
@@ -252,6 +253,12 @@ public class Tethering extends BaseNetworkObserver {
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
}
+ private void maybeUpdateConfiguration() {
+ final int dunCheck = TetheringConfiguration.checkDunRequired(mContext);
+ if (dunCheck == mConfig.dunCheck) return;
+ updateConfiguration();
+ }
+
@Override
public void interfaceStatusChanged(String iface, boolean up) {
// Never called directly: only called from interfaceLinkStateChanged.
@@ -1126,12 +1133,6 @@ public class Tethering extends BaseNetworkObserver {
}
}
- private void startOffloadController() {
- mOffloadController.start();
- mOffloadController.updateExemptPrefixes(
- mUpstreamNetworkMonitor.getOffloadExemptPrefixes());
- }
-
class TetherMasterSM extends StateMachine {
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
// an interface SM has requested Tethering/Local Hotspot
@@ -1149,14 +1150,14 @@ public class Tethering extends BaseNetworkObserver {
static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
- private State mInitialState;
- private State mTetherModeAliveState;
+ private final State mInitialState;
+ private final State mTetherModeAliveState;
- private State mSetIpForwardingEnabledErrorState;
- private State mSetIpForwardingDisabledErrorState;
- private State mStartTetheringErrorState;
- private State mStopTetheringErrorState;
- private State mSetDnsForwardersErrorState;
+ private final State mSetIpForwardingEnabledErrorState;
+ private final State mSetIpForwardingDisabledErrorState;
+ private final State mStartTetheringErrorState;
+ private final State mStopTetheringErrorState;
+ private final State mSetDnsForwardersErrorState;
// This list is a little subtle. It contains all the interfaces that currently are
// requesting tethering, regardless of whether these interfaces are still members of
@@ -1196,22 +1197,46 @@ public class Tethering extends BaseNetworkObserver {
mNotifyList = new ArrayList<>();
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
+
setInitialState(mInitialState);
}
+ private void startOffloadController() {
+ mOffloadController.start();
+ sendOffloadExemptPrefixes();
+ }
+
+ private void sendOffloadExemptPrefixes() {
+ sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
+ }
+
+ private void sendOffloadExemptPrefixes(Set<IpPrefix> localPrefixes) {
+ // Add in well-known minimum set.
+ PrefixUtils.addNonForwardablePrefixes(localPrefixes);
+ // Add tragically hardcoded prefixes.
+ localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
+
+ // Add prefixes for all downstreams, regardless of IP serving mode.
+ for (TetherInterfaceStateMachine tism : mNotifyList) {
+ localPrefixes.addAll(PrefixUtils.localPrefixesFrom(tism.linkProperties()));
+ }
+
+ mOffloadController.setLocalPrefixes(localPrefixes);
+ }
+
class InitialState extends State {
@Override
public boolean processMessage(Message message) {
logMessage(this, message.what);
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
transitionTo(mTetherModeAliveState);
break;
case EVENT_IFACE_SERVING_STATE_INACTIVE:
- who = (TetherInterfaceStateMachine)message.obj;
+ who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
break;
@@ -1273,7 +1298,9 @@ public class Tethering extends BaseNetworkObserver {
}
protected void chooseUpstreamType(boolean tryCell) {
- updateConfiguration(); // TODO - remove?
+ // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we
+ // do not currently know how to watch for changes in DUN settings.
+ maybeUpdateConfiguration();
final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
mConfig.preferredUpstreamIfaceTypes);
@@ -1404,8 +1431,8 @@ public class Tethering extends BaseNetworkObserver {
}
private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
- if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) {
- mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o);
+ if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
+ sendOffloadExemptPrefixes((Set<IpPrefix>) o);
return;
}
@@ -1509,7 +1536,7 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
@@ -1523,7 +1550,7 @@ public class Tethering extends BaseNetworkObserver {
break;
}
case EVENT_IFACE_SERVING_STATE_INACTIVE: {
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
handleInterfaceServingStateInactive(who);
@@ -1555,6 +1582,9 @@ public class Tethering extends BaseNetworkObserver {
mOffloadController.notifyDownstreamLinkProperties(newLp);
} else {
mOffloadController.removeDownstreamInterface(newLp.getInterfaceName());
+ // Another interface might be in local-only hotspot mode;
+ // resend all local prefixes to the OffloadController.
+ sendOffloadExemptPrefixes();
}
break;
}
@@ -1596,7 +1626,7 @@ public class Tethering extends BaseNetworkObserver {
boolean retValue = true;
switch (message.what) {
case EVENT_IFACE_SERVING_STATE_ACTIVE:
- TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
+ TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
who.sendMessage(mErrorNotification);
break;
case CMD_CLEAR_ERROR:
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index a69e4caebd5d..b47386705a36 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -20,6 +20,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
import android.net.IpPrefix;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
import android.net.util.SharedLog;
@@ -27,8 +28,11 @@ import android.os.Handler;
import android.provider.Settings;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
/**
@@ -47,7 +51,13 @@ public class OffloadController {
private boolean mConfigInitialized;
private boolean mControlInitialized;
private LinkProperties mUpstreamLinkProperties;
+ // The complete set of offload-exempt prefixes passed in via Tethering from
+ // all upstream and downstream sources.
private Set<IpPrefix> mExemptPrefixes;
+ // A strictly "smaller" set of prefixes, wherein offload-approved prefixes
+ // (e.g. downstream on-link prefixes) have been removed and replaced with
+ // prefixes representing only the locally-assigned IP addresses.
+ private Set<String> mLastLocalPrefixStrs;
public OffloadController(Handler h, OffloadHardwareInterface hwi,
ContentResolver contentResolver, SharedLog log) {
@@ -55,6 +65,8 @@ public class OffloadController {
mHwInterface = hwi;
mContentResolver = contentResolver;
mLog = log.forSubComponent(TAG);
+ mExemptPrefixes = new HashSet<>();
+ mLastLocalPrefixStrs = new HashSet<>();
}
public void start() {
@@ -77,8 +89,36 @@ public class OffloadController {
mControlInitialized = mHwInterface.initOffloadControl(
new OffloadHardwareInterface.ControlCallback() {
@Override
- public void onOffloadEvent(int event) {
- mLog.log("got offload event: " + event);
+ public void onStarted() {
+ mLog.log("onStarted");
+ }
+
+ @Override
+ public void onStoppedError() {
+ mLog.log("onStoppedError");
+ }
+
+ @Override
+ public void onStoppedUnsupported() {
+ mLog.log("onStoppedUnsupported");
+ }
+
+ @Override
+ public void onSupportAvailable() {
+ mLog.log("onSupportAvailable");
+
+ // [1] Poll for statistics and notify NetworkStats
+ // [2] (Re)Push all state:
+ // [a] push local prefixes
+ // [b] push downstreams
+ // [c] push upstream parameters
+ pushUpstreamParameters();
+ }
+
+ @Override
+ public void onStoppedLimitReached() {
+ mLog.log("onStoppedLimitReached");
+ // Poll for statistics and notify NetworkStats
}
@Override
@@ -106,25 +146,22 @@ public class OffloadController {
}
public void setUpstreamLinkProperties(LinkProperties lp) {
- if (!started()) return;
+ if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
// TODO: examine return code and decide what to do if programming
// upstream parameters fails (probably just wait for a subsequent
// onOffloadEvent() callback to tell us offload is available again and
// then reapply all state).
+ computeAndPushLocalPrefixes();
pushUpstreamParameters();
}
- public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
+ public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
if (!started()) return;
- mExemptPrefixes = exemptPrefixes;
- // TODO:
- // - add IP addresses from all downstream link properties
- // - add routes from all non-tethering downstream link properties
- // - remove any 64share prefixes
- // - push this to the HAL
+ mExemptPrefixes = localPrefixes;
+ computeAndPushLocalPrefixes();
}
public void notifyDownstreamLinkProperties(LinkProperties lp) {
@@ -187,4 +224,42 @@ public class OffloadController {
return mHwInterface.setUpstreamParameters(
iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
}
+
+ private boolean computeAndPushLocalPrefixes() {
+ final Set<String> localPrefixStrs = computeLocalPrefixStrings(
+ mExemptPrefixes, mUpstreamLinkProperties);
+ if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
+
+ mLastLocalPrefixStrs = localPrefixStrs;
+ return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs));
+ }
+
+ // TODO: Factor in downstream LinkProperties once that information is available.
+ private static Set<String> computeLocalPrefixStrings(
+ Set<IpPrefix> localPrefixes, LinkProperties upstreamLinkProperties) {
+ // Create an editable copy.
+ final Set<IpPrefix> prefixSet = new HashSet<>(localPrefixes);
+
+ // TODO: If a downstream interface (not currently passed in) is reusing
+ // the /64 of the upstream (64share) then:
+ //
+ // [a] remove that /64 from the local prefixes
+ // [b] add in /128s for IP addresses on the downstream interface
+ // [c] add in /128s for IP addresses on the upstream interface
+ //
+ // Until downstream information is available here, simply add /128s from
+ // the upstream network; they'll just be redundant with their /64.
+ if (upstreamLinkProperties != null) {
+ for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) {
+ if (!linkAddr.isGlobalPreferred()) continue;
+ final InetAddress ip = linkAddr.getAddress();
+ if (!(ip instanceof Inet6Address)) continue;
+ prefixSet.add(new IpPrefix(ip, 128));
+ }
+ }
+
+ final HashSet<String> localPrefixStrs = new HashSet<>();
+ for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString());
+ return localPrefixStrs;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 913096cb5bef..4df566f03d6d 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.BitUtils.uint16;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
+import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.os.Handler;
import android.os.RemoteException;
import android.net.util.SharedLog;
@@ -53,7 +54,11 @@ public class OffloadHardwareInterface {
private ControlCallback mControlCallback;
public static class ControlCallback {
- public void onOffloadEvent(int event) {}
+ public void onStarted() {}
+ public void onStoppedError() {}
+ public void onStoppedUnsupported() {}
+ public void onSupportAvailable() {}
+ public void onStoppedLimitReached() {}
public void onNatTimeoutUpdate(int proto,
String srcAddr, int srcPort,
@@ -108,7 +113,7 @@ public class OffloadHardwareInterface {
(controlCb == null) ? "null"
: "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
- mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback);
+ mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
final CbResults results = new CbResults();
try {
mOffloadControl.initOffload(
@@ -163,6 +168,26 @@ public class OffloadHardwareInterface {
return stats;
}
+ public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
+ final String logmsg = String.format("setLocalPrefixes([%s])",
+ String.join(",", localPrefixes));
+
+ final CbResults results = new CbResults();
+ try {
+ mOffloadControl.setLocalPrefixes(localPrefixes,
+ (boolean success, String errMsg) -> {
+ results.success = success;
+ results.errMsg = errMsg;
+ });
+ } catch (RemoteException e) {
+ record(logmsg, e);
+ return false;
+ }
+
+ record(logmsg, results);
+ return results.success;
+ }
+
public boolean setUpstreamParameters(
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
iface = (iface != null) ? iface : NO_INTERFACE_NAME;
@@ -206,15 +231,37 @@ public class OffloadHardwareInterface {
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
public final Handler handler;
public final ControlCallback controlCb;
+ public final SharedLog log;
- public TetheringOffloadCallback(Handler h, ControlCallback cb) {
+ public TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
handler = h;
controlCb = cb;
+ log = sharedLog;
}
@Override
public void onEvent(int event) {
- handler.post(() -> { controlCb.onOffloadEvent(event); });
+ handler.post(() -> {
+ switch (event) {
+ case OffloadCallbackEvent.OFFLOAD_STARTED:
+ controlCb.onStarted();
+ break;
+ case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
+ controlCb.onStoppedError();
+ break;
+ case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
+ controlCb.onStoppedUnsupported();
+ break;
+ case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
+ controlCb.onSupportAvailable();
+ break;
+ case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
+ controlCb.onStoppedLimitReached();
+ break;
+ default:
+ log.e("Unsupported OffloadCallbackEvent: " + event);
+ }
+ });
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 4bac69ce7495..69678df4543d 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -161,6 +161,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
public int lastError() { return mLastError; }
+ public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
+
public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 9b034aef1e95..eb18b1220f5b 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -70,6 +70,7 @@ public class TetheringConfiguration {
public final String[] tetherableUsbRegexs;
public final String[] tetherableWifiRegexs;
public final String[] tetherableBluetoothRegexs;
+ public final int dunCheck;
public final boolean isDunRequired;
public final Collection<Integer> preferredUpstreamIfaceTypes;
public final String[] dhcpRanges;
@@ -85,7 +86,7 @@ public class TetheringConfiguration {
tetherableBluetoothRegexs = ctx.getResources().getStringArray(
com.android.internal.R.array.config_tether_bluetooth_regexs);
- final int dunCheck = checkDunRequired(ctx);
+ dunCheck = checkDunRequired(ctx);
configLog.log("DUN check returned: " + dunCheckString(dunCheck));
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
@@ -172,7 +173,7 @@ public class TetheringConfiguration {
return upstreamNames;
}
- private static int checkDunRequired(Context ctx) {
+ public static int checkDunRequired(Context ctx) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index eb66767bfdfa..c5f752807cb7 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -34,6 +34,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.util.NetworkConstants;
+import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.util.Log;
@@ -72,16 +73,11 @@ public class UpstreamNetworkMonitor {
private static final boolean DBG = false;
private static final boolean VDBG = false;
- private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = {
- prefix("127.0.0.0/8"), prefix("169.254.0.0/16"),
- prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"),
- };
-
public static final int EVENT_ON_AVAILABLE = 1;
public static final int EVENT_ON_CAPABILITIES = 2;
public static final int EVENT_ON_LINKPROPERTIES = 3;
public static final int EVENT_ON_LOST = 4;
- public static final int NOTIFY_EXEMPT_PREFIXES = 10;
+ public static final int NOTIFY_LOCAL_PREFIXES = 10;
private static final int CALLBACK_LISTEN_ALL = 1;
private static final int CALLBACK_TRACK_DEFAULT = 2;
@@ -93,7 +89,7 @@ public class UpstreamNetworkMonitor {
private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
- private HashSet<IpPrefix> mOffloadExemptPrefixes;
+ private HashSet<IpPrefix> mLocalPrefixes;
private ConnectivityManager mCM;
private NetworkCallback mListenAllCallback;
private NetworkCallback mDefaultNetworkCallback;
@@ -107,7 +103,7 @@ public class UpstreamNetworkMonitor {
mHandler = mTarget.getHandler();
mLog = log.forSubComponent(TAG);
mWhat = what;
- mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
+ mLocalPrefixes = new HashSet<>();
}
@VisibleForTesting
@@ -223,8 +219,8 @@ public class UpstreamNetworkMonitor {
return typeStatePair.ns;
}
- public Set<IpPrefix> getOffloadExemptPrefixes() {
- return (Set<IpPrefix>) mOffloadExemptPrefixes.clone();
+ public Set<IpPrefix> getLocalPrefixes() {
+ return (Set<IpPrefix>) mLocalPrefixes.clone();
}
private void handleAvailable(int callbackType, Network network) {
@@ -360,11 +356,11 @@ public class UpstreamNetworkMonitor {
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
}
- private void recomputeOffloadExemptPrefixes() {
- final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
- if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) {
- mOffloadExemptPrefixes = exemptPrefixes;
- notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone());
+ private void recomputeLocalPrefixes() {
+ final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
+ if (!mLocalPrefixes.equals(localPrefixes)) {
+ mLocalPrefixes = localPrefixes;
+ notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
}
}
@@ -402,7 +398,7 @@ public class UpstreamNetworkMonitor {
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
handleLinkProp(network, newLp);
- recomputeOffloadExemptPrefixes();
+ recomputeLocalPrefixes();
}
// TODO: Handle onNetworkSuspended();
@@ -411,7 +407,7 @@ public class UpstreamNetworkMonitor {
@Override
public void onLost(Network network) {
handleLost(mCallbackType, network);
- recomputeOffloadExemptPrefixes();
+ recomputeLocalPrefixes();
}
}
@@ -460,35 +456,15 @@ public class UpstreamNetworkMonitor {
return result;
}
- private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) {
+ private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
final HashSet<IpPrefix> prefixSet = new HashSet<>();
- addDefaultLocalPrefixes(prefixSet);
-
for (NetworkState ns : netStates) {
- addOffloadExemptPrefixes(prefixSet, ns.linkProperties);
+ final LinkProperties lp = ns.linkProperties;
+ if (lp == null) continue;
+ prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
}
return prefixSet;
}
-
- private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) {
- Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET);
- }
-
- private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) {
- if (lp == null) return;
-
- for (LinkAddress linkAddr : lp.getAllLinkAddresses()) {
- prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength()));
- }
-
- // TODO: Consider adding other non-default routes associated with this
- // network. Traffic to these destinations should perhaps not go through
- // the Internet (upstream).
- }
-
- private static IpPrefix prefix(String prefixStr) {
- return new IpPrefix(prefixStr);
- }
}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index e8dfd779a715..9b4999667c88 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -164,33 +164,29 @@ public class PackageTracker implements IntentHelper.Listener {
}
// Validate the updater application package.
- // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
- // after it is replaced by one in data so this check fails. http://b/35995024
- // try {
- // if (!mPackageManagerHelper.isPrivilegedApp(mUpdateAppPackageName)) {
- // throw failWithException(
- // "Update app " + mUpdateAppPackageName + " must be a priv-app.", null);
- // }
- // } catch (PackageManager.NameNotFoundException e) {
- // throw failWithException("Could not determine update app package details for "
- // + mUpdateAppPackageName, e);
- // }
+ try {
+ if (!mPackageManagerHelper.isPrivilegedApp(mUpdateAppPackageName)) {
+ throw logAndThrowRuntimeException(
+ "Update app " + mUpdateAppPackageName + " must be a priv-app.", null);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw logAndThrowRuntimeException("Could not determine update app package details for "
+ + mUpdateAppPackageName, e);
+ }
// TODO(nfuller) Consider permission checks. While an updated system app retains permissions
// obtained by the system version it's not clear how to check them.
Slog.d(TAG, "Update app " + mUpdateAppPackageName + " is valid.");
// Validate the data application package.
- // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
- // after it is replaced by one in data. http://b/35995024
- // try {
- // if (!mPackageManagerHelper.isPrivilegedApp(mDataAppPackageName)) {
- // throw failWithException(
- // "Data app " + mDataAppPackageName + " must be a priv-app.", null);
- // }
- // } catch (PackageManager.NameNotFoundException e) {
- // throw failWithException("Could not determine data app package details for "
- // + mDataAppPackageName, e);
- // }
+ try {
+ if (!mPackageManagerHelper.isPrivilegedApp(mDataAppPackageName)) {
+ throw logAndThrowRuntimeException(
+ "Data app " + mDataAppPackageName + " must be a priv-app.", null);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw logAndThrowRuntimeException("Could not determine data app package details for "
+ + mDataAppPackageName, e);
+ }
// TODO(nfuller) Consider permission checks. While an updated system app retains permissions
// obtained by the system version it's not clear how to check them.
Slog.d(TAG, "Data app " + mDataAppPackageName + " is valid.");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b2930a4d536d..adaf59974caf 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.net.DhcpResults;
import android.net.INetd;
import android.net.InterfaceConfiguration;
+import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties.ProvisioningChange;
import android.net.LinkProperties;
@@ -35,6 +36,7 @@ import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Message;
@@ -51,17 +53,25 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IState;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.net.NetlinkTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
import java.util.StringJoiner;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
@@ -308,6 +318,11 @@ public class IpManager extends StateMachine {
return this;
}
+ public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
+ mConfig.mInitialConfig = initialConfig;
+ return this;
+ }
+
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
mConfig.mStaticIpConfig = staticConfig;
return this;
@@ -342,18 +357,20 @@ public class IpManager extends StateMachine {
/* package */ boolean mEnableIPv6 = true;
/* package */ boolean mUsingIpReachabilityMonitor = true;
/* package */ int mRequestedPreDhcpActionMs;
+ /* package */ InitialConfiguration mInitialConfig;
/* package */ StaticIpConfiguration mStaticIpConfig;
/* package */ ApfCapabilities mApfCapabilities;
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
- public ProvisioningConfiguration() {}
+ public ProvisioningConfiguration() {} // used by Builder
public ProvisioningConfiguration(ProvisioningConfiguration other) {
mEnableIPv4 = other.mEnableIPv4;
mEnableIPv6 = other.mEnableIPv6;
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
+ mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
mStaticIpConfig = other.mStaticIpConfig;
mApfCapabilities = other.mApfCapabilities;
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
@@ -366,12 +383,124 @@ public class IpManager extends StateMachine {
.add("mEnableIPv6: " + mEnableIPv6)
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
+ .add("mInitialConfig: " + mInitialConfig)
.add("mStaticIpConfig: " + mStaticIpConfig)
.add("mApfCapabilities: " + mApfCapabilities)
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
.toString();
}
+
+ public boolean isValid() {
+ return (mInitialConfig == null) || mInitialConfig.isValid();
+ }
+ }
+
+ public static class InitialConfiguration {
+ public final Set<LinkAddress> ipAddresses = new HashSet<>();
+ public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
+ public final Set<InetAddress> dnsServers = new HashSet<>();
+ public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
+
+ public static InitialConfiguration copy(InitialConfiguration config) {
+ if (config == null) {
+ return null;
+ }
+ InitialConfiguration configCopy = new InitialConfiguration();
+ configCopy.ipAddresses.addAll(config.ipAddresses);
+ configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
+ configCopy.dnsServers.addAll(config.dnsServers);
+ return configCopy;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
+ join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
+ join(", ", dnsServers), gateway);
+ }
+
+ public boolean isValid() {
+ // For every IP address, there must be at least one prefix containing that address.
+ for (LinkAddress addr : ipAddresses) {
+ if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
+ return false;
+ }
+ }
+ // For every dns server, there must be at least one prefix containing that address.
+ for (InetAddress addr : dnsServers) {
+ if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
+ return false;
+ }
+ }
+ // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
+ // (read: compliant with RFC4291#section2.5.4).
+ if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
+ return false;
+ }
+ // If directlyConnectedRoutes contains an IPv6 default route
+ // then ipAddresses MUST contain at least one non-ULA GUA.
+ if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
+ && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
+ return false;
+ }
+ // The prefix length of routes in directlyConnectedRoutes be within reasonable
+ // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
+ if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
+ return false;
+ }
+ // There no more than one IPv4 address
+ if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean isPrefixLengthCompliant(LinkAddress addr) {
+ return (addr.getAddress() instanceof Inet4Address)
+ || isCompliantIPv6PrefixLength(addr.getPrefixLength());
+ }
+
+ private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
+ return (prefix.getAddress() instanceof Inet4Address)
+ || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
+ }
+
+ private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
+ return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
+ && (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
+ }
+
+ private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
+ return prefix.getAddress().equals(Inet6Address.ANY);
+ }
+
+ private static boolean isIPv6GUA(LinkAddress addr) {
+ return (addr.getAddress() instanceof Inet6Address) && addr.isGlobalPreferred();
+ }
+
+ private static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
+ for (T t : coll) {
+ if (fn.test(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
+ return !any(coll, not(fn));
+ }
+
+ private static <T> Predicate<T> not(Predicate<T> fn) {
+ return (t) -> !fn.test(t);
+ }
+
+ private static <T> String join(String delimiter, Collection<T> coll) {
+ return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
+ }
}
public static final String DUMP_ARG = "ipmanager";
@@ -436,8 +565,7 @@ public class IpManager extends StateMachine {
private boolean mMulticastFiltering;
private long mStartTimeMillis;
- public IpManager(Context context, String ifName, Callback callback)
- throws IllegalArgumentException {
+ public IpManager(Context context, String ifName, Callback callback) {
this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
}
@@ -446,7 +574,7 @@ public class IpManager extends StateMachine {
* An expanded constructor, useful for dependency injection.
*/
public IpManager(Context context, String ifName, Callback callback,
- INetworkManagementService nwService) throws IllegalArgumentException {
+ INetworkManagementService nwService) {
super(IpManager.class.getSimpleName() + "." + ifName);
mTag = getName();
@@ -563,6 +691,11 @@ public class IpManager extends StateMachine {
}
public void startProvisioning(ProvisioningConfiguration req) {
+ if (!req.isValid()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+ return;
+ }
+
getNetworkInterface();
mCallback.setNeighborDiscoveryOffload(true);
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index a012e0cb0547..9b3bc3f0301a 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -102,6 +102,7 @@ public final class NetworkConstants {
public static final int IPV6_ADDR_LEN = 16;
public static final int IPV6_MIN_MTU = 1280;
public static final int RFC7421_PREFIX_LENGTH = 64;
+ public static final int RFC6177_MIN_PREFIX_LENGTH = 48;
/**
* ICMPv6 constants.
diff --git a/services/net/java/android/net/util/PrefixUtils.java b/services/net/java/android/net/util/PrefixUtils.java
new file mode 100644
index 000000000000..962aab459a19
--- /dev/null
+++ b/services/net/java/android/net/util/PrefixUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.net.util;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * @hide
+ */
+public class PrefixUtils {
+ private static final IpPrefix[] MIN_NON_FORWARDABLE_PREFIXES = {
+ pfx("127.0.0.0/8"), // IPv4 loopback
+ pfx("169.254.0.0/16"), // IPv4 link-local, RFC3927#section-8
+ pfx("::/3"),
+ pfx("fe80::/64"), // IPv6 link-local
+ pfx("fc00::/7"), // IPv6 ULA
+ pfx("ff02::/8"), // IPv6 link-local multicast
+ };
+
+ public static final IpPrefix DEFAULT_WIFI_P2P_PREFIX = pfx("192.168.49.0/24");
+
+ public static Set<IpPrefix> getNonForwardablePrefixes() {
+ final HashSet<IpPrefix> prefixes = new HashSet<>();
+ addNonForwardablePrefixes(prefixes);
+ return prefixes;
+ }
+
+ public static void addNonForwardablePrefixes(Set<IpPrefix> prefixes) {
+ Collections.addAll(prefixes, MIN_NON_FORWARDABLE_PREFIXES);
+ }
+
+ public static Set<IpPrefix> localPrefixesFrom(LinkProperties lp) {
+ final HashSet<IpPrefix> localPrefixes = new HashSet<>();
+ if (lp == null) return localPrefixes;
+
+ for (LinkAddress addr : lp.getAllLinkAddresses()) {
+ if (addr.getAddress().isLinkLocalAddress()) continue;
+ localPrefixes.add(asIpPrefix(addr));
+ }
+ // TODO: Add directly-connected routes as well (ones from which we did
+ // not also form a LinkAddress)?
+
+ return localPrefixes;
+ }
+
+ public static IpPrefix asIpPrefix(LinkAddress addr) {
+ return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+ }
+
+ private static IpPrefix pfx(String prefixStr) {
+ return new IpPrefix(prefixStr);
+ }
+}
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
index 231f2c8660e9..4eeabb078a64 100644
--- a/telephony/java/android/telephony/MbmsDownloadManager.java
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
@@ -26,9 +27,9 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import android.telephony.mbms.FileInfo;
import android.telephony.mbms.IDownloadCallback;
import android.telephony.mbms.DownloadRequest;
-import android.telephony.mbms.DownloadStatus;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsDownloadReceiver;
@@ -40,6 +41,8 @@ import android.util.Log;
import java.io.File;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@@ -192,6 +195,18 @@ public class MbmsDownloadManager {
public static final int RESULT_EXPIRED = 3;
// TODO - more results!
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STATUS_UNKNOWN, STATUS_ACTIVELY_DOWNLOADING, STATUS_PENDING_DOWNLOAD,
+ STATUS_PENDING_REPAIR, STATUS_PENDING_DOWNLOAD_WINDOW})
+ public @interface DownloadStatus {}
+
+ public static final int STATUS_UNKNOWN = 0;
+ public static final int STATUS_ACTIVELY_DOWNLOADING = 1;
+ public static final int STATUS_PENDING_DOWNLOAD = 2;
+ public static final int STATUS_PENDING_REPAIR = 3;
+ public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4;
+
private final Context mContext;
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
@@ -271,17 +286,19 @@ public class MbmsDownloadManager {
* The serviceClasses argument lets the app filter on types of programming and is opaque data
* negotiated beforehand between the app and the carrier.
*
- * Multiple calls replace the list of serviceClasses of interest.
- *
* This may throw an {@link MbmsException} containing one of the following errors:
* {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
*
* Asynchronous error codes via the {@link MbmsDownloadManagerCallback#error(int, String)}
* callback can include any of the errors except:
- * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
- * {@link MbmsException#ERROR_END_OF_SESSION}
+ * {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE}
+ *
+ * @param classList A list of service classes which the app wishes to receive
+ * {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks
+ * about. Subsequent calls to this method will replace this list of service
+ * classes (i.e. the middleware will no longer send updates for services
+ * matching classes only in the old list).
*/
public void getFileServices(List<String> classList) throws MbmsException {
IMbmsDownloadService downloadService = mService.get();
@@ -296,7 +313,7 @@ public class MbmsDownloadManager {
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -312,9 +329,10 @@ public class MbmsDownloadManager {
* will default to a directory formed by the concatenation of the app's files directory and
* {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}.
*
- * This method may not be called while any download requests are still active. If this is
- * the case, an {@link MbmsException} will be thrown with code
- * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
+ * Before calling this method, the app must cancel all of its pending
+ * {@link DownloadRequest}s via {@link #cancelDownload(DownloadRequest)}. If this is not done,
+ * an {@link MbmsException} will be thrown with code
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
*
* The {@link File} supplied as a root temp file directory must already exist. If not, an
* {@link IllegalArgumentException} will be thrown.
@@ -346,7 +364,7 @@ public class MbmsDownloadManager {
}
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
SharedPreferences prefs = mContext.getSharedPreferences(
@@ -397,29 +415,36 @@ public class MbmsDownloadManager {
downloadService.download(request, callback);
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
/**
- * Returns a list DownloadRequests that originated from this application (UID).
- *
- * May throw a RemoteException.
- *
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_UNABLED_TO_START_SERVICE</li>
- * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
- * <li>ERROR_MSDC_END_OF_SESSION</li>
+ * Returns a list of pending {@link DownloadRequest}s that originated from this application.
+ * A pending request is one that was issued via
+ * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through
+ * {@link #cancelDownload(DownloadRequest)}.
+ * @return A list, possibly empty, of {@link DownloadRequest}s
*/
- public List<DownloadRequest> listPendingDownloads() {
- return null;
+ public @NonNull List<DownloadRequest> listPendingDownloads() throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ return downloadService.listPendingDownloads(mSubscriptionId);
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ }
}
/**
* Attempts to cancel the specified {@link DownloadRequest}.
*
* If the middleware is not aware of the specified download request, an MbmsException will be
- * thrown with error code {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
+ * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
*
* If this method returns without throwing an exception, you may assume that cancellation
* was successful.
@@ -438,45 +463,71 @@ public class MbmsDownloadManager {
}
} catch (RemoteException e) {
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
deleteDownloadRequestToken(downloadRequest);
}
/**
- * Gets information about current and known upcoming downloads.
+ * Gets information about the status of a file pending download.
*
- * Current is a straightforward count of the files being downloaded "now"
- * for some definition of now (may be racey).
- * Future downloads include counts of files with pending repair operations, counts of
- * files with future downloads and indication of scheduled download times with unknown
- * file details.
+ * If the middleware has not yet been properly initialized or if it has no records of the
+ * file indicated by {@code fileInfo} being associated with {@code downloadRequest},
+ * {@link #STATUS_UNKNOWN} will be returned.
*
- * May throw an IllegalArgumentException or RemoteException.
- *
- * If the DownloadRequest is unknown the results will be null.
+ * @param downloadRequest The download request to query.
+ * @param fileInfo The particular file within the request to get information on.
+ * @return The status of the download.
*/
- public DownloadStatus getDownloadStatus(DownloadRequest downloadRequest) {
- return null;
+ @DownloadStatus
+ public int getDownloadStatus(DownloadRequest downloadRequest, FileInfo fileInfo)
+ throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ return downloadService.getDownloadStatus(downloadRequest, fileInfo);
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ }
}
/**
- * Resets middleware knowledge regarding this download request.
+ * Resets the middleware's knowledge of previously-downloaded files in this download request.
*
- * This state consists of knowledge of what files have already been downloaded.
- * Normally the middleware won't download files who's hash matches previously downloaded
- * content, even if that content has since been deleted. If this function is called
- * repeated content will be downloaded again when available. This does not interrupt
- * in-progress downloads.
+ * Normally, the middleware keeps track of the hashes of downloaded files and won't re-download
+ * files whose server-reported hash matches one of the already-downloaded files. This means
+ * that if the file is accidentally deleted by the user or by the app, the middleware will
+ * not try to download it again.
+ * This method will reset the middleware's cache of hashes for the provided
+ * {@link DownloadRequest}, so that previously downloaded content will be downloaded again
+ * when available.
+ * This will not interrupt in-progress downloads.
*
- * May throw an IllegalArgumentException or RemoteException.
+ * If the middleware is not aware of the specified download request, an MbmsException will be
+ * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
*
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
- * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+ * May throw a {@link MbmsException} with error code
+ * @param downloadRequest The request to re-download files for.
*/
- public int resetDownloadKnowledge(DownloadRequest downloadRequest) {
- return 0;
+ public void resetDownloadKnowledge(DownloadRequest downloadRequest) throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ int result = downloadService.resetDownloadKnowledge(downloadRequest);
+ if (result != MbmsException.SUCCESS) {
+ throw new MbmsException(result);
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ }
}
public void dispose() {
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index 8cc447e4db7a..5b3503a1b163 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -35,7 +35,10 @@ import java.util.concurrent.atomic.AtomicReference;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-/** @hide */
+/**
+ * This class provides functionality for streaming media over MBMS.
+ * @hide
+ */
public class MbmsStreamingManager {
private static final String LOG_TAG = "MbmsStreamingManager";
public static final String MBMS_STREAMING_SERVICE_ACTION =
@@ -88,6 +91,8 @@ public class MbmsStreamingManager {
/**
* Terminates this instance, ending calls to the registered listener. Also terminates
* any streaming services spawned from this instance.
+ *
+ * May throw an {@link IllegalStateException}
*/
public void dispose() {
IMbmsStreamingService streamingService = mService.get();
@@ -111,15 +116,15 @@ public class MbmsStreamingManager {
*
* Multiple calls replace the list of serviceClasses of interest.
*
- * This may throw an {@link MbmsException} containing one of the following errors:
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * This may throw an {@link MbmsException} containing any error in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
*
- * Asynchronous error codes via the {@link MbmsStreamingManagerCallback#error(int, String)}
- * callback can include any of the errors except:
- * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
- * {@link MbmsException#ERROR_END_OF_SESSION}
+ * May also throw an unchecked {@link IllegalArgumentException} or an
+ * {@link IllegalStateException}
+ *
+ * @param classList A list of streaming service classes that the app would like updates on.
*/
public void getStreamingServices(List<String> classList) throws MbmsException {
IMbmsStreamingService streamingService = mService.get();
@@ -134,7 +139,7 @@ public class MbmsStreamingManager {
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -145,14 +150,21 @@ public class MbmsStreamingManager {
* reported via
* {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int, int)}
*
- * May throw an {@link MbmsException} containing any of the following error codes:
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * May throw an
+ * {@link MbmsException} containing any of the error codes in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}.
*
* May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * Asynchronous errors through the listener include any of the errors
+ * Asynchronous errors through the listener include any of the errors in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors} or
+ * {@link android.telephony.mbms.MbmsException.StreamingErrors}.
+ *
+ * @param serviceInfo The information about the service to stream.
+ * @param listener A listener that'll be called when something about the stream changes.
+ * @return An instance of {@link StreamingService} through which the stream can be controlled.
*/
public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
StreamingServiceCallback listener) throws MbmsException {
@@ -170,7 +182,7 @@ public class MbmsStreamingManager {
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService.set(null);
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
return new StreamingService(mSubscriptionId, streamingService, serviceInfo, listener);
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.aidl b/telephony/java/android/telephony/mbms/DownloadStatus.aidl
deleted file mode 100755
index e7cfd391dade..000000000000
--- a/telephony/java/android/telephony/mbms/DownloadStatus.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-** Copyright 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.telephony.mbms;
-
-parcelable DownloadStatus;
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.java b/telephony/java/android/telephony/mbms/DownloadStatus.java
deleted file mode 100644
index 90eb53f3f59e..000000000000
--- a/telephony/java/android/telephony/mbms/DownloadStatus.java
+++ /dev/null
@@ -1,77 +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.telephony.mbms;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A Parcelable class describing the status of a Cell-Broadcast download request
- * @hide
- */
-public class DownloadStatus implements Parcelable {
- // includes downloads and active repair work
- public final int activelyDownloading;
-
- // files scheduled for future broadcast
- public final int pendingDownloads;
-
- // files scheduled for future repairs
- public final int pendingRepairs;
-
- // is a future download window scheduled with unknown
- // number of files
- public final boolean windowPending;
-
- public DownloadStatus(int downloading, int downloads, int repairs, boolean window) {
- activelyDownloading = downloading;
- pendingDownloads = downloads;
- pendingRepairs = repairs;
- windowPending = window;
- }
-
- public static final Parcelable.Creator<DownloadStatus> CREATOR =
- new Parcelable.Creator<DownloadStatus>() {
- @Override
- public DownloadStatus createFromParcel(Parcel in) {
- return new DownloadStatus(in);
- }
-
- @Override
- public DownloadStatus[] newArray(int size) {
- return new DownloadStatus[size];
- }
- };
-
- DownloadStatus(Parcel in) {
- activelyDownloading = in.readInt();
- pendingDownloads = in.readInt();
- pendingRepairs = in.readInt();
- windowPending = (in.readInt() == 1);
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(activelyDownloading);
- dest.writeInt(pendingDownloads);
- dest.writeInt(pendingRepairs);
- dest.writeInt((windowPending ? 1 : 0));
- }
-
- public int describeContents() {
- return 0;
- }
-}
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
index 8116a7f0b7c4..007aee7cf3f2 100755
--- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
@@ -30,7 +30,5 @@ oneway interface IMbmsStreamingManagerCallback
void streamingServicesUpdated(in List<StreamingServiceInfo> services);
- void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services);
-
void middlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
index 5b22199bea1c..ba25f663ffb4 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
@@ -55,7 +55,7 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St
* Before this method is called, calling any method on an instance of
* {@link android.telephony.MbmsDownloadManager} will result in an {@link MbmsException}
* being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public void middlewareReady() {
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index e190623f5529..8888119f90e6 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -18,27 +18,112 @@ package android.telephony.mbms;
/** @hide */
public class MbmsException extends Exception {
+ /** Indicates that the operation was successful. */
public static final int SUCCESS = 0;
- public static final int ERROR_NO_SERVICE_INSTALLED = 1;
- public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2;
- public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3;
- public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 4;
- public static final int ERROR_ALREADY_INITIALIZED = 5;
- public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
- public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
- public static final int ERROR_UNABLE_TO_START_SERVICE = 8;
- public static final int ERROR_STREAM_ALREADY_STARTED = 9;
- public static final int ERROR_END_OF_SESSION = 10;
- public static final int ERROR_SERVICE_LOST = 11;
- public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 12;
- public static final int ERROR_IN_E911 = 13;
- public static final int ERROR_OUT_OF_MEMORY = 14;
- public static final int ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE = 15;
- public static final int ERROR_UNABLE_TO_READ_SIM = 16;
- public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 17;
- public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 18;
- public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 19;
- public static final int ERROR_UNABLE_TO_INITIALIZE = 20;
+
+ // Following errors are generated in the manager and should not be returned from the
+ // middleware
+ /**
+ * Indicates that either no MBMS middleware app is installed on the device or multiple
+ * middleware apps are installed on the device.
+ */
+ public static final int ERROR_NO_UNIQUE_MIDDLEWARE = 1;
+
+ /**
+ * Indicates that the app attempted to perform an operation on an instance of
+ * {@link android.telephony.MbmsDownloadManager} or
+ * {@link android.telephony.MbmsStreamingManager} without being bound to the middleware.
+ */
+ public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2;
+
+ /** Indicates that the middleware has died and the requested operation was not completed.*/
+ public static final int ERROR_MIDDLEWARE_LOST = 3;
+
+ /**
+ * Indicates errors that may be generated during initialization by the
+ * middleware. They are applicable to both streaming and file-download use-cases.
+ */
+ public static class InitializationErrors {
+ /**
+ * Indicates that the app tried to create more than one instance each of
+ * {@link android.telephony.MbmsStreamingManager} or
+ * {@link android.telephony.MbmsDownloadManager}.
+ */
+ public static final int ERROR_DUPLICATE_INITIALIZE = 101;
+ /** Indicates that the app is not authorized to access media via MBMS.*/
+ public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102;
+ /** Indicates that the middleware was unable to initialize for this app. */
+ public static final int ERROR_UNABLE_TO_INITIALIZE = 103;
+ }
+
+ /**
+ * Indicates the errors that may occur at any point and are applicable to both
+ * streaming and file-download.
+ */
+ public static class GeneralErrors {
+ /**
+ * Indicates that the app attempted to perform an operation before receiving notification
+ * that the middleware is ready via {@link MbmsStreamingManagerCallback#middlewareReady()}
+ * or {@link MbmsDownloadManagerCallback#middlewareReady()}.
+ */
+ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201;
+ /**
+ * Indicates that the middleware ran out of memory and was unable to complete the requested
+ * operation.
+ */
+ public static final int ERROR_OUT_OF_MEMORY = 202;
+ /**
+ * Indicates that the requested operation failed due to the middleware being unavailable due
+ * to a transient condition. The app may retry the operation at a later time.
+ */
+ public static final int ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 203;
+ /**
+ * Indicates that the requested operation was not performed due to being in emergency
+ * callback mode.
+ */
+ public static final int ERROR_IN_E911 = 204;
+ /** Indicates that MBMS is not available due to the device being in roaming. */
+ public static final int ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE = 205;
+ /** Indicates that MBMS is not available due to a SIM read error. */
+ public static final int ERROR_UNABLE_TO_READ_SIM = 206;
+ /**
+ * Indicates that MBMS is not available due to the inserted SIM being from an unsupported
+ * carrier.
+ */
+ public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 207;
+ }
+
+ /**
+ * Indicates the errors that are applicable only to the streaming use-case
+ */
+ public static class StreamingErrors {
+ /** Indicates that the middleware cannot start a stream due to too many ongoing streams */
+ public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301;
+
+ /** Indicates that the middleware was unable to start the streaming service */
+ public static final int ERROR_UNABLE_TO_START_SERVICE = 302;
+
+ /**
+ * Indicates that the app called
+ * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
+ * more than once for the same {@link StreamingServiceInfo}.
+ */
+ public static final int ERROR_DUPLICATE_START_STREAM = 303;
+ }
+
+ /**
+ * Indicates the errors that are applicable only to the file-download use-case
+ */
+ public static class DownloadErrors {
+ /**
+ * Indicates that the app is not allowed to change the temp file root at this time due to
+ * outstanding download requests.
+ */
+ public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 401;
+
+ /** Indicates that the middleware has no record of the supplied {@link DownloadRequest}. */
+ public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 402;
+ }
private final int mErrorCode;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
index 27d9878a1966..2e91be9acaf7 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -50,25 +50,12 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.
}
/**
- * Called to indicate the active Streaming Services have changed.
- *
- * This will be caused whenever a new service starts streaming or whenever
- * MbmsStreamServiceManager.getActiveStreamingServices is called.
- *
- * @param services a list of StreamingServiceInfos. May be empty if
- * there are no active StreamingServices
- */
- public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) {
- // default implementation empty
- }
-
- /**
* Called to indicate that the middleware has been initialized and is ready.
*
* Before this method is called, calling any method on an instance of
* {@link android.telephony.MbmsStreamingManager} will result in an {@link MbmsException}
* being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public void middlewareReady() {
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 1e03fb9584b4..4b913f825231 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -22,14 +22,11 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.*;
import android.content.pm.ServiceInfo;
-import android.telephony.MbmsDownloadManager;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* @hide
@@ -78,7 +75,7 @@ public class MbmsUtils {
MbmsUtils.getMiddlewareServiceInfo(context, serviceAction);
if (mbmsServiceInfo == null) {
- throw new MbmsException(MbmsException.ERROR_NO_SERVICE_INSTALLED);
+ throw new MbmsException(MbmsException.ERROR_NO_UNIQUE_MIDDLEWARE);
}
bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo));
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 475c93aa0eb5..1a6418969a90 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -18,7 +18,6 @@ package android.telephony.mbms;
import android.annotation.IntDef;
import android.net.Uri;
-import android.os.DeadObjectException;
import android.os.RemoteException;
import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log;
@@ -50,15 +49,42 @@ public class StreamingService {
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({REASON_BY_USER_REQUEST, REASON_END_OF_SESSION, REASON_FREQUENCY_CONFLICT,
- REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE})
+ REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
+ REASON_LEFT_MBMS_BROADCAST_AREA})
public @interface StreamingStateChangeReason {}
+
+ /**
+ * State changed due to a call to {@link #stopStreaming()} or
+ * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
+ */
public static final int REASON_BY_USER_REQUEST = 1;
+
+ /**
+ * State changed due to the streaming session ending at the carrier.
+ */
public static final int REASON_END_OF_SESSION = 2;
+
+ /**
+ * State changed due to a frequency conflict with another requested stream.
+ */
public static final int REASON_FREQUENCY_CONFLICT = 3;
+
+ /**
+ * State changed due to the middleware running out of memory
+ */
public static final int REASON_OUT_OF_MEMORY = 4;
+
+ /**
+ * State changed due to the device leaving the home carrier's LTE network.
+ */
public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5;
/**
+ * State changed due to the device leaving the where this stream is being broadcast.
+ */
+ public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5;
+
+ /**
* The method of transmission currently used for a stream,
* reported via {@link StreamingServiceCallback#streamMethodUpdated}
*/
@@ -87,7 +113,9 @@ public class StreamingService {
* Retreive the Uri used to play this stream.
*
* This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ *
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
* @return The {@link Uri} to pass to the streaming client.
*/
@@ -101,7 +129,7 @@ public class StreamingService {
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
@@ -115,7 +143,9 @@ public class StreamingService {
/**
* Stop streaming this service.
* This may throw a {@link MbmsException} with the error code
- * {@link MbmsException#ERROR_SERVICE_LOST}
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ *
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*/
public void stopStreaming() throws MbmsException {
if (mService == null) {
@@ -127,10 +157,18 @@ public class StreamingService {
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
}
}
+ /**
+ * Disposes of this stream. Further operations on this object will fail with an
+ * {@link IllegalStateException}.
+ *
+ * This may throw a {@link MbmsException} with the error code
+ * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ */
public void dispose() throws MbmsException {
if (mService == null) {
throw new IllegalStateException("No streaming service attached");
@@ -140,8 +178,9 @@ public class StreamingService {
mService.disposeStream(mSubscriptionId, mServiceInfo.getServiceId());
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+ } finally {
mService = null;
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
}
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index 7112e13d5650..725d11c880b2 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -19,12 +19,11 @@ package android.telephony.mbms.vendor;
import android.app.PendingIntent;
import android.net.Uri;
import android.telephony.mbms.DownloadRequest;
-import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.FileInfo;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
import android.telephony.mbms.IDownloadCallback;
/**
- * The interface the opaque MbmsStreamingService will satisfy.
* @hide
*/
interface IMbmsDownloadService
@@ -41,14 +40,9 @@ interface IMbmsDownloadService
int cancelDownload(in DownloadRequest downloadRequest);
- DownloadStatus getDownloadStatus(in DownloadRequest downloadRequest);
+ int getDownloadStatus(in DownloadRequest downloadRequest, in FileInfo fileInfo);
- /*
- * named this for 2 reasons:
- * 1 don't want 'State' here as it conflicts with 'Status' of the previous function
- * 2 want to perfect typing 'Knowledge'
- */
- void resetDownloadKnowledge(in DownloadRequest downloadRequest);
+ int resetDownloadKnowledge(in DownloadRequest downloadRequest);
void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index 1370b83857ec..04a53cbe0d00 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -22,12 +22,11 @@ import android.telephony.mbms.IStreamingServiceCallback;
import android.telephony.mbms.StreamingServiceInfo;
/**
- * The interface the opaque MbmsStreamingService will satisfy.
* @hide
*/
interface IMbmsStreamingService
{
- int initialize(IMbmsStreamingManagerCallback listener, int subId);
+ void initialize(IMbmsStreamingManagerCallback listener, int subId);
int getStreamingServices(int subId, in List<String> serviceClasses);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 58bda6480999..8fbd4481cfc2 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -16,9 +16,10 @@
package android.telephony.mbms.vendor;
+import android.annotation.NonNull;
import android.os.RemoteException;
import android.telephony.mbms.DownloadRequest;
-import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.FileInfo;
import android.telephony.mbms.IDownloadCallback;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsException;
@@ -35,7 +36,9 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
/**
* Initialize the download service for this app and subId, registering the listener.
*
- * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ * Exceptions should not be thrown through this method -- this method is called from within a
+ * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
+ * catching them. Call {@link IMbmsDownloadManagerCallback#error(int, String)} instead.
*
* @param listener The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use.
@@ -59,9 +62,8 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
* @param serviceClasses The service classes that the app wishes to get info on. The strings
* may contain arbitrary data as negotiated between the app and the
* carrier.
- * @return One of {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * @return One of {@link MbmsException#SUCCESS} or
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY},
*/
@Override
public int getFileServices(int subscriptionId, List<String> serviceClasses)
@@ -73,11 +75,16 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
* Sets the temp file root directory for this app/subscriptionId combination. The middleware
* should persist {@code rootDirectoryPath} and send it back when sending intents to the
* app's {@link android.telephony.mbms.MbmsDownloadReceiver}.
+ *
+ * If the calling app (as identified by the calling UID) currently has any pending download
+ * requests that have not been canceled, the middleware must return
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} here.
+ *
* @param subscriptionId The subscription id the download is operating under.
* @param rootDirectoryPath The path to the app's temp file root directory.
- * @return {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT},
- * or {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * @return {@link MbmsException#SUCCESS},
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} or
+ * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
*/
@Override
public int setTempFileRootDirectory(int subscriptionId,
@@ -87,6 +94,11 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
/**
* Issues a request to download a set of files.
+ *
+ * The middleware should expect that {@link #setTempFileRootDirectory(int, String)} has been
+ * called for this app between when the app was installed and when this method is called. If
+ * this is not the case, an {@link IllegalStateException} may be thrown.
+ *
* @param downloadRequest An object describing the set of files to be downloaded.
* @param listener A listener through which the middleware can provide progress updates to
* the app while both are still running.
@@ -98,8 +110,18 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
return 0;
}
+
+ /**
+ * Returns a list of pending {@link DownloadRequest}s that originated from the calling
+ * application, identified by its uid. A pending request is one that was issued via
+ * {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through
+ * {@link #cancelDownload(DownloadRequest)}.
+ * The middleware must return a non-null result synchronously or throw an exception
+ * inheriting from {@link RuntimeException}.
+ * @return A list, possibly empty, of {@link DownloadRequest}s
+ */
@Override
- public List<DownloadRequest> listPendingDownloads(int subscriptionId)
+ public @NonNull List<DownloadRequest> listPendingDownloads(int subscriptionId)
throws RemoteException {
return null;
}
@@ -113,23 +135,47 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
* {@link DownloadRequest}.
* @param downloadRequest The request to cancel
* @return {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST},
+ * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/
@Override
public int cancelDownload(DownloadRequest downloadRequest) throws RemoteException {
return 0;
}
+ /**
+ * Gets information about the status of a file pending download.
+ *
+ * If the middleware has not yet been properly initialized or if it has no records of the
+ * file indicated by {@code fileInfo} being associated with {@code downloadRequest},
+ * {@link android.telephony.MbmsDownloadManager#STATUS_UNKNOWN} must be returned.
+ *
+ * @param downloadRequest The download request to query.
+ * @param fileInfo The particular file within the request to get information on.
+ * @return The status of the download.
+ */
@Override
- public DownloadStatus getDownloadStatus(DownloadRequest downloadRequest)
+ public int getDownloadStatus(DownloadRequest downloadRequest, FileInfo fileInfo)
throws RemoteException {
- return null;
+ return 0;
}
+ /**
+ * Resets the middleware's knowledge of previously-downloaded files in this download request.
+ *
+ * When this method is called, the middleware must attempt to re-download all the files
+ * specified by the {@link DownloadRequest}, even if the files have not changed on the server.
+ * In addition, current in-progress downloads must not be interrupted.
+ *
+ * If the middleware is not aware of the specified download request, return
+ * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
+ *
+ * @param downloadRequest The request to re-download files for.
+ */
@Override
- public void resetDownloadKnowledge(DownloadRequest downloadRequest)
+ public int resetDownloadKnowledge(DownloadRequest downloadRequest)
throws RemoteException {
+ return 0;
}
/**
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index c97e754d1dd5..f072c46171d6 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -33,16 +33,17 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
/**
* Initialize streaming service for this app and subId, registering the listener.
*
- * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ * Exceptions should not be thrown through this method -- this method is called from within a
+ * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
+ * catching them. Call {@link IMbmsStreamingManagerCallback#error(int, String)} instead.
*
* @param listener The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use.
- * @return {@link MbmsException#SUCCESS} or {@link MbmsException#ERROR_ALREADY_INITIALIZED}
*/
@Override
- public int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
+ public void initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
throws RemoteException {
- return 0;
+ return;
}
/**
@@ -59,9 +60,8 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* @param serviceClasses The service classes that the app wishes to get info on. The strings
* may contain arbitrary data as negotiated between the app and the
* carrier.
- * @return One of {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
- * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * @return {@link MbmsException#SUCCESS} or any of the errors in
+ * {@link android.telephony.mbms.MbmsException.GeneralErrors}
*/
@Override
public int getStreamingServices(int subscriptionId,
@@ -79,8 +79,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app has requested.
* @param listener The listener object on which the app wishes to receive updates.
- * @return {@link MbmsException#SUCCESS}, {@link MbmsException#ERROR_STREAM_ALREADY_STARTED},
- * or {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}.
+ * @return Any error in {@link android.telephony.mbms.MbmsException.GeneralErrors}
*/
@Override
public int startStreaming(int subscriptionId, String serviceId,
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
index 025b01740aad..e7dbfe3f5044 100644
--- a/tests/net/java/android/net/ip/IpManagerTest.java
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -16,11 +16,26 @@
package android.net.ip;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.ip.IpManager.Callback;
+import android.net.ip.IpManager.InitialConfiguration;
+import android.net.ip.IpManager.ProvisioningConfiguration;
import android.os.INetworkManagementService;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
@@ -31,11 +46,17 @@ import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.R;
import org.junit.Before;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Tests for IpManager.
*/
@@ -44,14 +65,20 @@ import org.mockito.MockitoAnnotations;
public class IpManagerTest {
private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
+ private static final String VALID = "VALID";
+ private static final String INVALID = "INVALID";
+
@Mock private Context mContext;
@Mock private INetworkManagementService mNMService;
@Mock private Resources mResources;
+ @Mock private Callback mCb;
+ @Mock private AlarmManager mAlarm;
private MockContentResolver mContentResolver;
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
@@ -68,7 +95,152 @@ public class IpManagerTest {
@Test
public void testInvalidInterfaceDoesNotThrow() throws Exception {
- final IpManager.Callback cb = new IpManager.Callback();
- final IpManager ipm = new IpManager(mContext, "test_wlan0", cb, mNMService);
+ final IpManager ipm = new IpManager(mContext, "test_wlan0", mCb, mNMService);
+ }
+
+ @Test
+ public void testDefaultProvisioningConfiguration() throws Exception {
+ final String iface = "test_wlan0";
+ final IpManager ipm = new IpManager(mContext, iface, mCb, mNMService);
+ ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+ .withoutIPv4()
+ // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
+ // and enable it in this test
+ .withoutIpReachabilityMonitor()
+ .build();
+
+ ipm.startProvisioning(config);
+ verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
+ verify(mCb, timeout(100).times(1)).setFallbackMulticastFilter(false);
+ verify(mCb, never()).onProvisioningFailure(any());
+
+ ipm.stop();
+ verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
+ verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
+ }
+
+ @Test
+ public void testInitialConfigurations() throws Exception {
+ InitialConfigurationTestCase[] testcases = {
+ validConf("valid IPv4 configuration",
+ links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
+ validConf("another valid IPv4 configuration",
+ links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
+ validConf("valid IPv6 configurations",
+ links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
+ prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
+ dns("2001:db8:dead:beef:f00::02")),
+ validConf("valid IPv6 configurations",
+ links("fe80::1/64"), prefixes("fe80::/64"), dns()),
+ validConf("valid IPv6/v4 configuration",
+ links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
+ prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
+ dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
+ validConf("valid IPv6 configuration without any GUA.",
+ links("fd00:1234:5678::1/48"),
+ prefixes("fd00:1234:5678::/48"),
+ dns("fd00:1234:5678::1000")),
+
+ invalidConf("v4 addr and dns not in any prefix",
+ links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
+ invalidConf("v4 addr not in any prefix",
+ links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
+ invalidConf("v4 dns addr not in any prefix",
+ links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
+ invalidConf("v6 addr not in any prefix",
+ links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
+ prefixes("2001:db8:dead:beef::/64"),
+ dns("2001:db8:dead:beef:f00::02")),
+ invalidConf("v6 dns addr not in any prefix",
+ links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
+ invalidConf("default ipv6 route and no GUA",
+ links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
+ invalidConf("invalid v6 prefix length",
+ links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
+ dns()),
+ invalidConf("another invalid v6 prefix length",
+ links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
+ dns())
+ };
+
+ for (InitialConfigurationTestCase testcase : testcases) {
+ if (testcase.config.isValid() != testcase.isValid) {
+ fail(testcase.errorMessage());
+ }
+ }
+ }
+
+ static class InitialConfigurationTestCase {
+ String descr;
+ boolean isValid;
+ InitialConfiguration config;
+ public String errorMessage() {
+ return String.format("%s: expected configuration %s to be %s, but was %s",
+ descr, config, validString(isValid), validString(!isValid));
+ }
+ }
+
+ static String validString(boolean isValid) {
+ return isValid ? VALID : INVALID;
+ }
+
+ static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
+ Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+ return confTestCase(descr, true, conf(links, prefixes, dns));
+ }
+
+ static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
+ Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+ return confTestCase(descr, false, conf(links, prefixes, dns));
+ }
+
+ static InitialConfigurationTestCase confTestCase(
+ String descr, boolean isValid, InitialConfiguration config) {
+ InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
+ testcase.descr = descr;
+ testcase.isValid = isValid;
+ testcase.config = config;
+ return testcase;
+ }
+
+ static InitialConfiguration conf(
+ Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+ InitialConfiguration conf = new InitialConfiguration();
+ conf.ipAddresses.addAll(links);
+ conf.directlyConnectedRoutes.addAll(prefixes);
+ conf.dnsServers.addAll(dns);
+ return conf;
+ }
+
+ static Set<IpPrefix> prefixes(String... prefixes) {
+ return mapIntoSet(prefixes, IpPrefix::new);
+ }
+
+ static Set<LinkAddress> links(String... addresses) {
+ return mapIntoSet(addresses, LinkAddress::new);
+ }
+
+ static Set<InetAddress> ips(String... addresses) {
+ return mapIntoSet(addresses, InetAddress::getByName);
+ }
+
+ static Set<InetAddress> dns(String... addresses) {
+ return ips(addresses);
+ }
+
+ static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
+ Set<B> out = new HashSet<>(in.length);
+ for (A item : in) {
+ try {
+ out.add(fn.call(item));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return out;
+ }
+
+ interface Fn<A,B> {
+ B call(A a) throws Exception;
}
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index c3313f8cb2ce..789ce6c3092a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
@@ -45,6 +46,8 @@ import com.android.internal.util.test.FakeSettingsProvider;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
import org.junit.After;
import org.junit.Before;
@@ -186,17 +189,43 @@ public class OffloadControllerTest {
any(OffloadHardwareInterface.ControlCallback.class));
inOrder.verifyNoMoreInteractions();
+ // In reality, the UpstreamNetworkMonitor would have passed down to us
+ // a covering set of local prefixes representing a minimum essential
+ // set plus all the prefixes on networks with network agents.
+ //
+ // We simulate that there, and then add upstream elements one by one
+ // and watch what happens.
+ final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
+ for (String s : new String[]{
+ "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
+ minimumLocalPrefixes.add(new IpPrefix(s));
+ }
+ offload.setLocalPrefixes(minimumLocalPrefixes);
+ inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
+ ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
+ assertEquals(4, localPrefixes.size());
+ assertTrue(localPrefixes.contains("127.0.0.0/8"));
+ assertTrue(localPrefixes.contains("192.0.2.0/24"));
+ assertTrue(localPrefixes.contains("fe80::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::/64"));
+ inOrder.verifyNoMoreInteractions();
+
offload.setUpstreamLinkProperties(null);
- inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(null), eq(null), eq(null), eq(null));
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
+ // This LinkProperties value does not differ from the default upstream.
+ // There should be no extraneous call to setUpstreamParameters().
+ inOrder.verify(mHardware, never()).setUpstreamParameters(
+ anyObject(), anyObject(), anyObject(), anyObject());
inOrder.verifyNoMoreInteractions();
- reset(mHardware);
final LinkProperties lp = new LinkProperties();
final String testIfName = "rmnet_data17";
lp.setInterfaceName(testIfName);
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(null), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
@@ -204,7 +233,15 @@ public class OffloadControllerTest {
final String ipv4Addr = "192.0.2.5";
final String linkAddr = ipv4Addr + "/24";
lp.addLinkAddress(new LinkAddress(linkAddr));
+ lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24")));
offload.setUpstreamLinkProperties(lp);
+ // IPv4 prefixes and addresses on the upstream are simply left as whole
+ // prefixes (already passed in from UpstreamNetworkMonitor code). If a
+ // tethering client sends traffic to the IPv4 default router or other
+ // clients on the upstream this will not be hardware-forwarded, and that
+ // should be fine for now. Ergo: no change in local addresses, no call
+ // to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
@@ -212,6 +249,8 @@ public class OffloadControllerTest {
final String ipv4Gateway = "192.0.2.1";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
inOrder.verifyNoMoreInteractions();
@@ -219,6 +258,8 @@ public class OffloadControllerTest {
final String ipv6Gw1 = "fe80::cafe";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
ArrayList<String> v6gws = mStringArrayCaptor.getValue();
@@ -229,6 +270,8 @@ public class OffloadControllerTest {
final String ipv6Gw2 = "fe80::d00d";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2)));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
v6gws = mStringArrayCaptor.getValue();
@@ -244,6 +287,8 @@ public class OffloadControllerTest {
stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00")));
assertTrue(lp.addStackedLink(stacked));
offload.setUpstreamLinkProperties(lp);
+ // No change in local addresses means no call to setLocalPrefixes().
+ inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture());
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
v6gws = mStringArrayCaptor.getValue();
@@ -251,5 +296,43 @@ public class OffloadControllerTest {
assertTrue(v6gws.contains(ipv6Gw1));
assertTrue(v6gws.contains(ipv6Gw2));
inOrder.verifyNoMoreInteractions();
+
+ // Add in some IPv6 upstream info. When there is a tethered downstream
+ // making use of the IPv6 prefix we would expect to see the /64 route
+ // removed from "local prefixes" and /128s added for the upstream IPv6
+ // addresses. This is not yet implemented, and for now we simply
+ // expect to see these /128s.
+ lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64")));
+ // "2001:db8::/64" plus "assigned" ASCII in hex
+ lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64"));
+ // "2001:db8::/64" plus "random" ASCII in hex
+ lp.addLinkAddress(new LinkAddress("2001:db8::7261:6e64:6f6d/64"));
+ offload.setUpstreamLinkProperties(lp);
+ inOrder.verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
+ localPrefixes = mStringArrayCaptor.getValue();
+ assertEquals(6, localPrefixes.size());
+ assertTrue(localPrefixes.contains("127.0.0.0/8"));
+ assertTrue(localPrefixes.contains("192.0.2.0/24"));
+ assertTrue(localPrefixes.contains("fe80::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::/64"));
+ assertTrue(localPrefixes.contains("2001:db8::6173:7369:676e:6564/128"));
+ assertTrue(localPrefixes.contains("2001:db8::7261:6e64:6f6d/128"));
+ // The relevant parts of the LinkProperties have not changed, but at the
+ // moment we do not de-dup upstream LinkProperties this carefully.
+ inOrder.verify(mHardware, times(1)).setUpstreamParameters(
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
+ v6gws = mStringArrayCaptor.getValue();
+ assertEquals(2, v6gws.size());
+ assertTrue(v6gws.contains(ipv6Gw1));
+ assertTrue(v6gws.contains(ipv6Gw2));
+ inOrder.verifyNoMoreInteractions();
+
+ // Completely identical LinkProperties updates are de-duped.
+ offload.setUpstreamLinkProperties(lp);
+ // This LinkProperties value does not differ from the default upstream.
+ // There should be no extraneous call to setUpstreamParameters().
+ inOrder.verify(mHardware, never()).setUpstreamParameters(
+ anyObject(), anyObject(), anyObject(), anyObject());
+ inOrder.verifyNoMoreInteractions();
}
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 69c93b14a486..c3b9defdec4e 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -324,19 +324,14 @@ public class UpstreamNetworkMonitorTest {
}
@Test
- public void testOffloadExemptPrefixes() throws Exception {
+ public void testLocalPrefixes() throws Exception {
mUNM.start();
- // [0] Test minimum set of exempt prefixes.
- Set<IpPrefix> exempt = mUNM.getOffloadExemptPrefixes();
- final String[] MINSET = {
- "127.0.0.0/8", "169.254.0.0/16",
- "::/3", "fe80::/64", "fc00::/7", "ff00::/8",
- };
- assertPrefixSet(exempt, INCLUDES, MINSET);
+ // [0] Test minimum set of local prefixes.
+ Set<IpPrefix> local = mUNM.getLocalPrefixes();
+ assertTrue(local.isEmpty());
+
final Set<String> alreadySeen = new HashSet<>();
- Collections.addAll(alreadySeen, MINSET);
- assertEquals(alreadySeen.size(), exempt.size());
// [1] Pretend Wi-Fi connects.
final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
@@ -355,15 +350,15 @@ public class UpstreamNetworkMonitorTest {
wifiAgent.fakeConnect();
wifiAgent.sendLinkProperties(wifiLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] wifiLinkPrefixes = {
- // Excludes link-local as that's already tested within MINSET.
+ // Link-local prefixes are excluded and dealt with elsewhere.
"100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
};
- assertPrefixSet(exempt, INCLUDES, wifiLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, wifiLinkPrefixes);
Collections.addAll(alreadySeen, wifiLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [2] Pretend mobile connects.
final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
@@ -379,12 +374,12 @@ public class UpstreamNetworkMonitorTest {
cellAgent.fakeConnect();
cellAgent.sendLinkProperties(cellLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
- assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
Collections.addAll(alreadySeen, cellLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [3] Pretend DUN connects.
final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
@@ -401,21 +396,20 @@ public class UpstreamNetworkMonitorTest {
dunAgent.fakeConnect();
dunAgent.sendLinkProperties(dunLp);
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, INCLUDES, alreadySeen);
final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
- assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
Collections.addAll(alreadySeen, dunLinkPrefixes);
- assertEquals(alreadySeen.size(), exempt.size());
+ assertEquals(alreadySeen.size(), local.size());
// [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
// longer be included (should be properly removed).
wifiAgent.fakeDisconnect();
- exempt = mUNM.getOffloadExemptPrefixes();
- assertPrefixSet(exempt, INCLUDES, MINSET);
- assertPrefixSet(exempt, EXCLUDES, wifiLinkPrefixes);
- assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
- assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ local = mUNM.getLocalPrefixes();
+ assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
+ assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
}
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {