Merge "Source of deadlock between PlayerBase.mLock and   PlaybackActivityMonitor.mPlayerLock:"
diff --git a/Android.bp b/Android.bp
index 98e52a9..254c5fc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -991,3 +991,27 @@
         ":hwbinder-stubs-docs",
     ],
 }
+
+filegroup {
+    name: "apache-http-stubs-sources",
+    srcs: [
+        "core/java/org/apache/http/conn/ConnectTimeoutException.java",
+        "core/java/org/apache/http/conn/scheme/HostNameResolver.java",
+        "core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java",
+        "core/java/org/apache/http/conn/scheme/SocketFactory.java",
+        "core/java/org/apache/http/conn/ssl/AbstractVerifier.java",
+        "core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java",
+        "core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java",
+        "core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java",
+        "core/java/org/apache/http/conn/ssl/SSLSocketFactory.java",
+        "core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java",
+        "core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java",
+        "core/java/org/apache/http/params/CoreConnectionPNames.java",
+        "core/java/org/apache/http/params/HttpConnectionParams.java",
+        "core/java/org/apache/http/params/HttpParams.java",
+        "core/java/android/net/http/HttpResponseCache.java",
+        "core/java/android/net/http/SslCertificate.java",
+        "core/java/android/net/http/SslError.java",
+        "core/java/com/android/internal/util/HexDump.java",
+    ],
+}
diff --git a/api/current.txt b/api/current.txt
index 7f076cb..b9ae497 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35306,6 +35306,7 @@
     field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
     field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
     field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
     field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
@@ -35411,7 +35412,6 @@
     field public static final deprecated java.lang.String RADIO_NFC = "nfc";
     field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
     field public static final java.lang.String RINGTONE = "ringtone";
-    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
     field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
     field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
     field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index 8ef12b45..709b37e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -440,6 +440,12 @@
     method public void setCdmaSystemAndNetworkId(int, int);
   }
 
+  public class TelephonyManager {
+    method public int getCarrierIdListVersion();
+    method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2b5353d..534f9c4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3673,17 +3673,6 @@
         public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
 
         /**
-         * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
-         * calls when supported by the device and carrier. Boolean value.
-         * 0 = OFF
-         * 1 = ON
-         */
-        public static final String RTT_CALLING_MODE = "rtt_calling_mode";
-
-        /** @hide */
-        public static final Validator RTT_CALLING_MODE_VALIDATOR = sBooleanValidator;
-
-        /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
@@ -4003,7 +3992,6 @@
             DTMF_TONE_WHEN_DIALING,
             DTMF_TONE_TYPE_WHEN_DIALING,
             HEARING_AID,
-            RTT_CALLING_MODE,
             TTY_MODE,
             MASTER_MONO,
             SOUND_EFFECTS_ENABLED,
@@ -4187,7 +4175,6 @@
             VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
             VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
             VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
-            VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
             VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
             VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
@@ -6262,6 +6249,15 @@
         public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
 
         /**
+         * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+         * calls when supported by the device and carrier. Boolean value.
+         * 0 = OFF
+         * 1 = ON
+         */
+        public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+
+        /**
+        /**
          * Controls whether settings backup is enabled.
          * Type: int ( 0 = disabled, 1 = enabled )
          * @hide
@@ -7218,6 +7214,7 @@
             PREFERRED_TTY_MODE,
             ENHANCED_VOICE_PRIVACY_ENABLED,
             TTY_MODE_ENABLED,
+            RTT_CALLING_MODE,
             INCALL_POWER_BUTTON_BEHAVIOR,
             NIGHT_DISPLAY_CUSTOM_START_TIME,
             NIGHT_DISPLAY_CUSTOM_END_TIME,
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7f6d19b..bd6ad2c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -810,12 +810,6 @@
         addOption("-Ximage-compiler-option");
         addOption("--image-classes=/system/etc/preloaded-classes");
 
-        // If there is a compiled-classes file, push it.
-        if (hasFile("/system/etc/compiled-classes")) {
-            addOption("-Ximage-compiler-option");
-            addOption("--compiled-classes=/system/etc/compiled-classes");
-        }
-
         // If there is a dirty-image-objects file, push it.
         if (hasFile("/system/etc/dirty-image-objects")) {
             addOption("-Ximage-compiler-option");
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0af187c..f2fe654 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -56,6 +56,8 @@
     </privapp-permissions>
 
     <privapp-permissions package="com.android.emergency">
+        <!-- Required to place emergency calls from emergency info screen. -->
+        <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.MANAGE_USERS"/>
     </privapp-permissions>
 
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 92a09d3..92d3709 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -522,7 +522,7 @@
                     ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
         }
 
-        // Note that this parses RA and may throw IllegalArgumentException (from
+        // Note that this parses RA and may throw InvalidRaException (from
         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
         // specifications.
@@ -986,9 +986,8 @@
      */
     @GuardedBy("this")
     private ApfGenerator beginProgramLocked() throws IllegalInstructionException {
-        ApfGenerator gen = new ApfGenerator();
-        // This is guaranteed to return true because of the check in maybeCreate.
-        gen.setApfVersion(mApfCapabilities.apfVersionSupported);
+        // This is guaranteed to succeed because of the check in maybeCreate.
+        ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
 
         // Here's a basic summary of what the initial program does:
         //
@@ -1215,7 +1214,7 @@
         //   1. the program generator will need its offsets adjusted.
         //   2. the packet filter attached to our packet socket will need its offset adjusted.
         if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
-        if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) {
+        if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java
index ca8f727..fcfb19c 100644
--- a/services/net/java/android/net/apf/ApfGenerator.java
+++ b/services/net/java/android/net/apf/ApfGenerator.java
@@ -58,7 +58,9 @@
         JLT(18),   // Compare less than and branch, e.g. "jlt R0,5,label"
         JSET(19),  // Compare any bits set and branch, e.g. "jset R0,5,label"
         JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455"
-        EXT(21);   // Followed by immediate indicating ExtendedOpcodes.
+        EXT(21),   // Followed by immediate indicating ExtendedOpcodes.
+        LDDW(22),  // Load 4 bytes from data memory address (register + immediate): "lddw R0, [5]R1"
+        STDW(23);  // Store 4 bytes to data memory address (register + immediate): "stdw R0, [5]R1"
 
         final int value;
 
@@ -355,19 +357,38 @@
      */
     public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT;
 
+    // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
+    private static final int MIN_APF_VERSION = 2;
+
     private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>();
     private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>();
     private final Instruction mDropLabel = new Instruction(Opcodes.LABEL);
     private final Instruction mPassLabel = new Instruction(Opcodes.LABEL);
+    private final int mVersion;
     private boolean mGenerated;
 
     /**
-     * Set version of APF instruction set to generate instructions for. Returns {@code true}
-     * if generating for this version is supported, {@code false} otherwise.
+     * Creates an ApfGenerator instance which is able to emit instructions for the specified
+     * {@code version} of the APF interpreter. Throws {@code IllegalInstructionException} if
+     * the requested version is unsupported.
      */
-    public boolean setApfVersion(int version) {
-        // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
-        return version >= 2;
+    ApfGenerator(int version) throws IllegalInstructionException {
+        mVersion = version;
+        requireApfVersion(MIN_APF_VERSION);
+    }
+
+    /**
+     * Returns true if the specified {@code version} is supported by the ApfGenerator, otherwise
+     * false.
+     */
+    public static boolean supportsVersion(int version) {
+        return version >= MIN_APF_VERSION;
+    }
+
+    private void requireApfVersion(int minimumVersion) throws IllegalInstructionException {
+        if (mVersion < minimumVersion) {
+            throw new IllegalInstructionException("Requires APF >= " + minimumVersion);
+        }
     }
 
     private void addInstruction(Instruction instruction) {
@@ -819,6 +840,36 @@
     }
 
     /**
+     * Add an instruction to the end of the program to load 32 bits from the data memory into
+     * {@code register}. The source address is computed by adding @{code offset} to the other
+     * register.
+     * Requires APF v3 or greater.
+     */
+    public ApfGenerator addLoadData(Register destinationRegister, int offset)
+            throws IllegalInstructionException {
+        requireApfVersion(3);
+        Instruction instruction = new Instruction(Opcodes.LDDW, destinationRegister);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to store 32 bits from {@code register} into the
+     * data memory. The destination address is computed by adding @{code offset} to the other
+     * register.
+     * Requires APF v3 or greater.
+     */
+    public ApfGenerator addStoreData(Register sourceRegister, int offset)
+            throws IllegalInstructionException {
+        requireApfVersion(3);
+        Instruction instruction = new Instruction(Opcodes.STDW, sourceRegister);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
      * Updates instruction offset fields using latest instruction sizes.
      * @return current program length in bytes.
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 49094604..f55061a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -27,6 +27,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
@@ -1035,6 +1036,13 @@
     public static final int UNKNOWN_CARRIER_ID = -1;
 
     /**
+     * An unknown carrier id list version.
+     * @hide
+     */
+    @TestApi
+    public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1;
+
+    /**
      * Broadcast Action: The subscription carrier identity has changed.
      * This intent could be sent on the following events:
      * <ul>
@@ -7756,4 +7764,49 @@
             }
         }
     }
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+     * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+            String gid2, String plmn, String spn) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setCarrierTestOverride(
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+    }
+
+    /**
+     * A test API to return installed carrier id list version
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public int getCarrierIdListVersion() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCarrierIdListVersion(getSubId());
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID_LIST_VERSION;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1ace032..9b71b8a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1481,4 +1481,17 @@
      * screen is off) we want to turn on those indications even when the screen is off.
      */
     void setRadioIndicationUpdateMode(int subId, int filters, int mode);
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+     * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+     */
+    void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
+            String gid2, String plmn, String spn);
+
+    /**
+     * A test API to return installed carrier id list version.
+     */
+    int getCarrierIdListVersion(int subId);
 }
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 4d149f7..a0e3985 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -81,3 +81,38 @@
         "junit",
     ],
 }
+
+droiddoc {
+    name: "android-test-base-api-stubs-gen-docs",
+    srcs: [
+        "src/**/*.java",
+    ],
+    custom_template: "droiddoc-templates-sdk",
+    installable: false,
+    args: "-stubpackages android.test:" +
+          "android.test.suitebuilder.annotation:" +
+          "com.android.internal.util:" +
+          "junit.framework -stubsourceonly -nodocs",
+    sdk_version: "current",
+    api_tag_name: "ANDROID_TEST_BASE",
+    api_filename: "android-test-base-api.txt",
+    removed_api_filename: "android-test-base-removed.txt",
+}
+
+// Build the android.test.base.stubs library
+// =========================================
+java_library_static {
+    name: "android.test.base.stubs",
+    srcs: [
+        ":android-test-base-api-stubs-gen-docs",
+    ],
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+        unbundled_build: {
+            enabled: false,
+        },
+    },
+    sdk_version: "current",
+}
diff --git a/test-base/Android.mk b/test-base/Android.mk
index ebb33de..baf5726 100644
--- a/test-base/Android.mk
+++ b/test-base/Android.mk
@@ -19,59 +19,10 @@
 # For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
 ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
 
-# Generate the stub source files for android.test.base.stubs
-# ==========================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
-
-ANDROID_TEST_BASE_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/api.txt
-ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/removed.txt
-
 ANDROID_TEST_BASE_API_FILE := $(LOCAL_PATH)/api/android-test-base-current.txt
 ANDROID_TEST_BASE_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-base-removed.txt
 
-LOCAL_DROIDDOC_OPTIONS:= \
-    -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \
-    -stubsourceonly \
-    -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.base.stubs_intermediates/src \
-    -nodocs \
-    -api $(ANDROID_TEST_BASE_OUTPUT_API_FILE) \
-    -removedApi $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := android-test-base-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-android_test_base_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(ANDROID_TEST_BASE_OUTPUT_API_FILE): $(full_target)
-$(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the android.test.base.stubs library
-# =========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.base.stubs
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SDK_VERSION := current
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_base_gen_stamp)
-android_test_base_gen_stamp :=
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
+full_classes_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,android.test.base.stubs,,COMMON)/classes.jar
 # Archive a copy of the classes.jar in SDK build.
 $(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.base.stubs.jar)
 
@@ -83,16 +34,16 @@
 $(eval $(call check-api, \
     check-android-test-base-api-current, \
     $(ANDROID_TEST_BASE_API_FILE), \
-    $(ANDROID_TEST_BASE_OUTPUT_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_BASE_API_FILE), \
     $(ANDROID_TEST_BASE_REMOVED_API_FILE), \
-    $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_BASE_REMOVED_API_FILE), \
     -error 2 -error 3 -error 4 -error 5 -error 6 \
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
     -error 25 -error 26 -error 27, \
     cat $(LOCAL_PATH)/api/apicheck_msg_android_test_base.txt, \
     check-android-test-base-api, \
-    $(call doc-timestamp-for,android-test-base-api-stubs-gen) \
+    $(OUT_DOCS)/android-test-base-api-stubs-gen-docs-stubs.srcjar \
     ))
 
 .PHONY: check-android-test-base-api
@@ -101,11 +52,11 @@
 .PHONY: update-android-test-base-api
 update-api: update-android-test-base-api
 
-update-android-test-base-api: $(ANDROID_TEST_BASE_OUTPUT_API_FILE) | $(ACP)
+update-android-test-base-api: $(INTERNAL_PLATFORM_ANDROID_TEST_BASE_API_FILE) | $(ACP)
 	@echo Copying current.txt
-	$(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_API_FILE) $(ANDROID_TEST_BASE_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_BASE_API_FILE) $(ANDROID_TEST_BASE_API_FILE)
 	@echo Copying removed.txt
-	$(hide) $(ACP) $(ANDROID_TEST_BASE_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_BASE_REMOVED_API_FILE) $(ANDROID_TEST_BASE_REMOVED_API_FILE)
 
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
 
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 54e07a16..8fb6fda 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -40,3 +40,49 @@
     // Pin java_version until jarjar is certified to support later versions. http://b/72703434
     java_version: "1.8",
 }
+
+doc_defaults {
+    name:"android.test.mock.docs-defaults",
+    srcs: ["src/android/test/mock/**/*.java"],
+
+    // Includes the main framework source to ensure that doclava has access to the
+    // visibility information for the base classes of the mock classes. Without it
+    // otherwise hidden methods could be visible.
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["core/java"],
+    srcs_lib_whitelist_pkgs: ["android"],
+    libs: [
+        "core-oj",
+        "core-libart",
+        "framework",
+        "conscrypt",
+        "okhttp",
+        "bouncycastle",
+        "ext",
+    ],
+    local_sourcepaths: ["src/android/test/mock"],
+    custom_template: "droiddoc-templates-sdk",
+    installable: false,
+}
+
+android_test_mock_docs_args =
+    "-hide 110 -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128 " +
+    "-stubpackages android.test.mock " +
+    "-nodocs "
+
+droiddoc {
+    name: "android.test.mock.docs",
+    defaults: ["android.test.mock.docs-defaults"],
+
+    api_tag_name: "ANDROID_TEST_MOCK",
+    api_filename: "api/android-test-mock-current.txt",
+    removed_api_filename: "api/android-test-mock-removed.txt",
+
+    args: android_test_mock_docs_args,
+}
+
+java_library_static {
+    name: "android.test.mock.stubs",
+    srcs: [":android.test.mock.docs"],
+    sdk_version: "current",
+}
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index 15fa12d1..08443c9 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -16,85 +16,30 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# Includes the main framework source to ensure that doclava has access to the
-# visibility information for the base classes of the mock classes. Without it
-# otherwise hidden methods could be visible.
-android_test_mock_source_files := \
-    $(call all-java-files-under, src/android/test/mock) \
-    $(call all-java-files-under, ../core/java/android)
-
-# Generate the stub source files for android.test.mock.stubs
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(android_test_mock_source_files)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework conscrypt okhttp bouncycastle
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
-
-ANDROID_TEST_MOCK_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/api.txt
-ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/removed.txt
-
-ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
-ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
-
-LOCAL_DROIDDOC_OPTIONS:= \
-    -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-    -stubpackages android.test.mock \
-    -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
-    -nodocs \
-    -api $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) \
-    -removedApi $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := android-test-mock-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-android_test_mock_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(ANDROID_TEST_MOCK_OUTPUT_API_FILE): $(full_target)
-$(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the android.test.mock.stubs library
-# =========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.stubs
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
-android_test_mock_gen_stamp :=
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
 # Archive a copy of the classes.jar in SDK build.
+full_classes_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,android.test.mock.stubs,,COMMON)/classes.jar
 $(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.stubs.jar)
 
 # Check that the android.test.mock.stubs library has not changed
 # ==============================================================
+ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
+ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
 
 # Check that the API we're building hasn't changed from the not-yet-released
 # SDK version.
 $(eval $(call check-api, \
     check-android-test-mock-api-current, \
     $(ANDROID_TEST_MOCK_API_FILE), \
-    $(ANDROID_TEST_MOCK_OUTPUT_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_MOCK_API_FILE), \
     $(ANDROID_TEST_MOCK_REMOVED_API_FILE), \
-    $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE), \
+    $(INTERNAL_PLATFORM_ANDROID_TEST_MOCK_REMOVED_API_FILE), \
     -error 2 -error 3 -error 4 -error 5 -error 6 \
     -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
     -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
     -error 25 -error 26 -error 27, \
     cat $(LOCAL_PATH)/api/apicheck_msg_android_test_mock.txt, \
     check-android-test-mock-api, \
-    $(call doc-timestamp-for,android-test-mock-api-stubs-gen) \
+    $(OUT_DOCS)/android.test.mock.docs-stubs.srcjar \
     ))
 
 .PHONY: check-android-test-mock-api
@@ -103,8 +48,8 @@
 .PHONY: update-android-test-mock-api
 update-api: update-android-test-mock-api
 
-update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP)
+update-android-test-mock-api: $(INTERNAL_PLATFORM_ANDROID_TEST_MOCK_API_FILE) | $(ACP)
 	@echo Copying current.txt
-	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_MOCK_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
 	@echo Copying removed.txt
-	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
+	$(hide) $(ACP) $(INTERNAL_PLATFORM_ANDROID_TEST_MOCK_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index a2edb04..9e95369 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -31,7 +31,7 @@
     libs: [
         "framework",
         "android.test.base",
-        "android.test.mock",
+        "android.test.mock.stubs",
     ],
 }
 
@@ -48,7 +48,7 @@
     libs: [
         "framework",
         "android.test.base",
-        "android.test.mock",
+        "android.test.mock.stubs",
         "junit",
     ],
 }
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 9364ec8..082f310 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -30,7 +30,6 @@
 import android.content.Context;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.NetworkUtils;
 import android.net.apf.ApfFilter.ApfConfiguration;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
@@ -42,22 +41,13 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.format.DateUtils;
-
 import com.android.frameworks.tests.net.R;
 import com.android.internal.util.HexDump;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -68,9 +58,14 @@
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Random;
-
 import libcore.io.IoUtils;
 import libcore.io.Streams;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 /**
  * Tests for APF program generator and interpreter.
@@ -82,6 +77,7 @@
 @SmallTest
 public class ApfTest {
     private static final int TIMEOUT_MS = 500;
+    private final static int MIN_APF_VERSION = 2;
 
     @Mock IpConnectivityLog mLog;
     @Mock Context mContext;
@@ -131,11 +127,11 @@
     }
 
     private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge));
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
     }
 
     private void assertVerdict(int expected, byte[] program, byte[] packet) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, 0));
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
     }
 
     private void assertPass(byte[] program, byte[] packet, int filterAge) {
@@ -154,9 +150,24 @@
         assertVerdict(DROP, program, packet);
     }
 
+  private void assertDataMemoryContents(
+          int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
+      throws IllegalInstructionException, Exception {
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
+
+        // assertArrayEquals() would only print one byte, making debugging difficult.
+        if (!java.util.Arrays.equals(expected_data, data)) {
+            throw new Exception(
+                    "program: " + HexDump.toHexString(program) +
+                    "\ndata memory: " + HexDump.toHexString(data) +
+                    "\nexpected: " + HexDump.toHexString(expected_data));
+        }
+    }
+
     private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
             throws IllegalInstructionException {
-        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
+        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
+              filterAge));
     }
 
     private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
@@ -189,11 +200,11 @@
         // Empty program should pass because having the program counter reach the
         // location immediately after the program indicates the packet should be
         // passed to the AP.
-        ApfGenerator gen = new ApfGenerator();
+        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
         assertPass(gen);
 
         // Test jumping to pass label.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJump(gen.PASS_LABEL);
         byte[] program = gen.generate();
         assertEquals(1, program.length);
@@ -201,7 +212,7 @@
         assertPass(program, new byte[MIN_PKT_SIZE], 0);
 
         // Test jumping to drop label.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJump(gen.DROP_LABEL);
         program = gen.generate();
         assertEquals(2, program.length);
@@ -210,121 +221,121 @@
         assertDrop(program, new byte[15], 15);
 
         // Test jumping if equal to 0.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if not equal to 0.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if registers equal.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if registers not equal.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test load immediate.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test add.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addAdd(1234567890);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test subtract.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addAdd(-1234567890);
         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test or.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addOr(1234567890);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test and.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addAnd(123456789);
         gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test left shift.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLeftShift(1);
         gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test right shift.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addRightShift(1);
         gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test multiply.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addMul(2);
         gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test divide.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addDiv(2);
         gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test divide by zero.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addDiv(0);
         gen.addJump(gen.DROP_LABEL);
         assertPass(gen);
 
         // Test add.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1234567890);
         gen.addAddR1();
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test subtract.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, -1234567890);
         gen.addAddR1();
         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test or.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1234567890);
         gen.addOrR1();
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test and.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLoadImmediate(Register.R1, 123456789);
         gen.addAndR1();
@@ -332,7 +343,7 @@
         assertDrop(gen);
 
         // Test left shift.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addLeftShiftR1();
@@ -340,7 +351,7 @@
         assertDrop(gen);
 
         // Test right shift.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLoadImmediate(Register.R1, -1);
         gen.addLeftShiftR1();
@@ -348,7 +359,7 @@
         assertDrop(gen);
 
         // Test multiply.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLoadImmediate(Register.R1, 2);
         gen.addMulR1();
@@ -356,7 +367,7 @@
         assertDrop(gen);
 
         // Test divide.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addLoadImmediate(Register.R1, 2);
         gen.addDivR1();
@@ -364,136 +375,136 @@
         assertDrop(gen);
 
         // Test divide by zero.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addDivR1();
         gen.addJump(gen.DROP_LABEL);
         assertPass(gen);
 
         // Test byte load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoad8(Register.R0, 1);
         gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test out of bounds load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoad8(Register.R0, 16);
         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test half-word load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoad16(Register.R0, 1);
         gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test word load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoad32(Register.R0, 1);
         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test byte indexed load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addLoad8Indexed(Register.R0, 0);
         gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test out of bounds indexed load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 8);
         gen.addLoad8Indexed(Register.R0, 8);
         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test half-word indexed load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addLoad16Indexed(Register.R0, 0);
         gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test word indexed load.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addLoad32Indexed(Register.R0, 0);
         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
 
         // Test jumping if greater than.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if less than.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if any bits set.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
         assertDrop(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 3);
         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if register greater than.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 2);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if register less than.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1);
         gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jumping if any bits set in register.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 3);
         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
         assertPass(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 3);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
         assertDrop(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 3);
         gen.addLoadImmediate(Register.R0, 3);
         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test load from memory.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadFromMemory(Register.R0, 0);
         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test store to memory.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1234567890);
         gen.addStoreToMemory(Register.R1, 12);
         gen.addLoadFromMemory(Register.R0, 12);
@@ -501,63 +512,63 @@
         assertDrop(gen);
 
         // Test filter age pre-filled memory.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
 
         // Test packet size pre-filled memory.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
         gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test IPv4 header size pre-filled memory.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
         gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
         assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
 
         // Test not.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addNot(Register.R0);
         gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test negate.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addNeg(Register.R0);
         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test move.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1234567890);
         gen.addMove(Register.R0);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addMove(Register.R1);
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test swap.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R1, 1234567890);
         gen.addSwap();
         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
         assertDrop(gen);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1234567890);
         gen.addSwap();
         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
         assertDrop(gen);
 
         // Test jump if bytes not equal.
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
         program = gen.generate();
@@ -569,25 +580,152 @@
         assertEquals(1, program[4]);
         assertEquals(123, program[5]);
         assertDrop(program, new byte[MIN_PKT_SIZE], 0);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
         byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
         assertPass(gen, packet123, 0);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
         assertDrop(gen, packet123, 0);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
         byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
         assertDrop(gen, packet12345, 0);
-        gen = new ApfGenerator();
+        gen = new ApfGenerator(MIN_APF_VERSION);
         gen.addLoadImmediate(Register.R0, 1);
         gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
         assertPass(gen, packet12345, 0);
     }
 
+    @Test(expected = ApfGenerator.IllegalInstructionException.class)
+    public void testApfGeneratorWantsV2OrGreater() throws Exception {
+        // The minimum supported APF version is 2.
+        new ApfGenerator(1);
+    }
+
+    @Test
+    public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
+        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
+        try {
+            gen.addStoreData(Register.R0, 0);
+            fail();
+        } catch (IllegalInstructionException expected) {
+            /* pass */
+        }
+        try {
+            gen.addLoadData(Register.R0, 0);
+            fail();
+        } catch (IllegalInstructionException expected) {
+            /* pass */
+        }
+    }
+
+    @Test
+    public void testApfDataWrite() throws IllegalInstructionException, Exception {
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
+        byte[] expected_data = data.clone();
+
+        // No memory access instructions: should leave the data segment untouched.
+        ApfGenerator gen = new ApfGenerator(3);
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+
+        // Expect value 0x87654321 to be stored starting from address 3 + 2, in big-endian order.
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 0x87654321);
+        gen.addLoadImmediate(Register.R1, 2);
+        gen.addStoreData(Register.R0, 3);
+        expected_data[5] = (byte)0x87;
+        expected_data[6] = (byte)0x65;
+        expected_data[7] = (byte)0x43;
+        expected_data[8] = (byte)0x21;
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
+    @Test
+    public void testApfDataRead() throws IllegalInstructionException, Exception {
+        // Program that DROPs if address 11 (7 + 3) contains 0x87654321.
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadData(Register.R0, 7);
+        gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
+        byte[] program = gen.generate();
+        byte[] packet = new byte[MIN_PKT_SIZE];
+
+        // Content is incorrect (last byte does not match) -> PASS
+        byte[] data = new byte[32];
+        data[10] = (byte)0x87;
+        data[11] = (byte)0x65;
+        data[12] = (byte)0x43;
+        data[13] = (byte)0x00;  // != 0x21
+        byte[] expected_data = data.clone();
+        assertDataMemoryContents(PASS, program, packet, data, expected_data);
+
+        // Fix the last byte -> conditional jump taken -> DROP
+        data[13] = (byte)0x21;
+        expected_data = data;
+        assertDataMemoryContents(DROP, program, packet, data, expected_data);
+    }
+
+    @Test
+    public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadData(Register.R0, 7);  // Load from address 7 + 3 = 10
+        gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
+        gen.addStoreData(Register.R0, 11);  // Write back to address 11 + 3 = 14
+
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = new byte[32];
+        data[10] = (byte)0x87;
+        data[11] = (byte)0x65;
+        data[12] = (byte)0x43;
+        data[13] = (byte)0x21;
+        byte[] expected_data = data.clone();
+        expected_data[14] = (byte)0xFF;
+        expected_data[15] = (byte)0xAA;
+        expected_data[16] = (byte)0x77;
+        expected_data[17] = (byte)0x33;
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
+    @Test
+    public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = new byte[32];
+        byte[] expected_data = data;
+
+        // Program that DROPs unconditionally. This is our the baseline.
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addLoadData(Register.R1, 7);
+        gen.addJump(gen.DROP_LABEL);
+        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
+
+        // Same program as before, but this time we're trying to load past the end of the data.
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, 15);  // 20 + 15 > 32
+        gen.addJump(gen.DROP_LABEL);  // Not reached.
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+
+        // Subtracting an immediate should work...
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, -4);
+        gen.addJump(gen.DROP_LABEL);
+        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
+
+        // ...but underflowing isn't allowed.
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, -30);
+        gen.addJump(gen.DROP_LABEL);  // Not reached.
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
     /**
      * Generate some BPF programs, translate them to APF, then run APF and BPF programs
      * over packet traces and verify both programs filter out the same packets.
@@ -1422,10 +1560,11 @@
     }
 
     /**
-     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
-     * filter was installed {@code filter_age} seconds ago.
+     * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
+     * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
      */
-    private native static int apfSimulate(byte[] program, byte[] packet, int filter_age);
+    private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
+        int filter_age);
 
     /**
      * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
diff --git a/tests/net/java/android/net/apf/Bpf2Apf.java b/tests/net/java/android/net/apf/Bpf2Apf.java
index 220e54d..5d57cde 100644
--- a/tests/net/java/android/net/apf/Bpf2Apf.java
+++ b/tests/net/java/android/net/apf/Bpf2Apf.java
@@ -307,7 +307,7 @@
      * program and return it.
      */
     public static byte[] convert(String bpf) throws IllegalInstructionException {
-        ApfGenerator gen = new ApfGenerator();
+        ApfGenerator gen = new ApfGenerator(3);
         for (String line : bpf.split("\\n")) convertLine(line, gen);
         return gen.generate();
     }
@@ -320,7 +320,7 @@
         BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
         String line = null;
         StringBuilder responseData = new StringBuilder();
-        ApfGenerator gen = new ApfGenerator();
+        ApfGenerator gen = new ApfGenerator(3);
         while ((line = in.readLine()) != null) convertLine(line, gen);
         System.out.write(gen.generate());
     }
diff --git a/tests/net/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp
index 152e6c3..79444e3 100644
--- a/tests/net/jni/apf_jni.cpp
+++ b/tests/net/jni/apf_jni.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016, The Android Open Source Project
+ * Copyright 2018, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,15 +28,22 @@
 
 // JNI function acting as simply call-through to native APF interpreter.
 static jint com_android_server_ApfTest_apfSimulate(
-        JNIEnv* env, jclass, jbyteArray program, jbyteArray packet, jint filter_age) {
-    return accept_packet(
-            (uint8_t*)env->GetByteArrayElements(program, NULL),
-            env->GetArrayLength(program),
-            (uint8_t*)env->GetByteArrayElements(packet, NULL),
-            env->GetArrayLength(packet),
-            nullptr,
-            0,
-            filter_age);
+        JNIEnv* env, jclass, jbyteArray program, jbyteArray packet,
+        jbyteArray data, jint filter_age) {
+    uint8_t* program_raw = (uint8_t*)env->GetByteArrayElements(program, nullptr);
+    uint8_t* packet_raw = (uint8_t*)env->GetByteArrayElements(packet, nullptr);
+    uint8_t* data_raw = (uint8_t*)(data ? env->GetByteArrayElements(data, nullptr) : nullptr);
+    uint32_t program_len = env->GetArrayLength(program);
+    uint32_t packet_len = env->GetArrayLength(packet);
+    uint32_t data_len = data ? env->GetArrayLength(data) : 0;
+    jint result = accept_packet(program_raw, program_len, packet_raw,
+                                packet_len, data_raw, data_len, filter_age);
+    if (data) {
+        env->ReleaseByteArrayElements(data, (jbyte*)data_raw, 0 /* copy back */);
+    }
+    env->ReleaseByteArrayElements(packet, (jbyte*)packet_raw, JNI_ABORT);
+    env->ReleaseByteArrayElements(program, (jbyte*)program_raw, JNI_ABORT);
+    return result;
 }
 
 class ScopedPcap {
@@ -170,7 +177,7 @@
     }
 
     static JNINativeMethod gMethods[] = {
-            { "apfSimulate", "([B[BI)I",
+            { "apfSimulate", "([B[B[BI)I",
                     (void*)com_android_server_ApfTest_apfSimulate },
             { "compileToBpf", "(Ljava/lang/String;)Ljava/lang/String;",
                     (void*)com_android_server_ApfTest_compileToBpf },