Merge "Support Call Forwarding and Call Waiting APIs for voice call."
diff --git a/Android.bp b/Android.bp
index 9a0d542..feaafa3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -551,7 +551,7 @@
 genrule {
     name: "framework-statslog-gen",
     tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out)",
+    cmd: "$(location stats-log-api-gen) --java $(out) --worksource",
     out: ["android/util/StatsLogInternal.java"],
 }
 
@@ -660,6 +660,7 @@
         "core/java/android/annotation/RequiresPermission.java",
         "core/java/android/annotation/SystemApi.java",
         "core/java/android/annotation/TestApi.java",
+        "core/java/com/android/internal/annotations/GuardedBy.java",
     ],
 }
 // Build ext.jar
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c72e89b..88d94cc 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -75,9 +75,9 @@
     // Pushed atoms start at 2.
     oneof pushed {
         // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
-        BleScanStateChanged ble_scan_state_changed = 2;
+        BleScanStateChanged ble_scan_state_changed = 2 [(log_from_module) = "bluetooth"];
         ProcessStateChanged process_state_changed = 3;
-        BleScanResultReceived ble_scan_result_received = 4;
+        BleScanResultReceived ble_scan_result_received = 4 [(log_from_module) = "bluetooth"];
         SensorStateChanged sensor_state_changed = 5;
         GpsScanStateChanged gps_scan_state_changed = 6;
         SyncStateChanged sync_state_changed = 7;
@@ -141,7 +141,8 @@
         AppDied app_died = 65;
         ResourceConfigurationChanged resource_configuration_changed = 66;
         BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67;
-        BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68;
+        BluetoothConnectionStateChanged bluetooth_connection_state_changed =
+                68 [(log_from_module) = "bluetooth"];
         GpsSignalQualityChanged gps_signal_quality_changed = 69;
         UsbConnectorStateChanged usb_connector_state_changed = 70;
         SpeakerImpedanceReported speaker_impedance_reported = 71;
@@ -216,9 +217,12 @@
         RescuePartyResetReported rescue_party_reset_reported = 122;
         SignedConfigReported signed_config_reported = 123;
         GnssNiEventReported gnss_ni_event_reported = 124;
-        BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
-        BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
-        BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
+        BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event =
+                125 [(log_from_module) = "bluetooth"];
+        BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed =
+                126 [(log_from_module) = "bluetooth"];
+        BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed =
+                127 [(log_from_module) = "bluetooth"];
         AppDowngraded app_downgraded = 128;
         AppOptimizedAfterDowngraded app_optimized_after_downgraded = 129;
         LowStorageStateChanged low_storage_state_changed = 130;
@@ -242,23 +246,40 @@
         BiometricSystemHealthIssueDetected biometric_system_health_issue_detected = 148;
         BubbleUIChanged bubble_ui_changed = 149;
         ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
-        BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
-        BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed = 152;
-        BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed = 153;
-        BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed = 154;
-        BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported = 155;
-        BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported = 156;
-        BluetoothDeviceRssiReported bluetooth_device_rssi_reported = 157;
-        BluetoothDeviceFailedContactCounterReported bluetooth_device_failed_contact_counter_reported = 158;
-        BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported = 159;
-        BluetoothHciTimeoutReported bluetooth_hci_timeout_reported = 160;
-        BluetoothQualityReportReported bluetooth_quality_report_reported = 161;
-        BluetoothDeviceInfoReported bluetooth_device_info_reported = 162;
-        BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported = 163;
-        BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported = 164;
-        BluetoothBondStateChanged bluetooth_bond_state_changed = 165;
-        BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166;
-        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
+        BluetoothActiveDeviceChanged bluetooth_active_device_changed =
+                151 [(log_from_module) = "bluetooth"];
+        BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed =
+                152 [(log_from_module) = "bluetooth"];
+        BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed =
+                153 [(log_from_module) = "bluetooth"];
+        BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed =
+                154 [(log_from_module) = "bluetooth"];
+        BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported =
+                155 [(log_from_module) = "bluetooth"];
+        BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported =
+                156 [(log_from_module) = "bluetooth"];
+        BluetoothDeviceRssiReported bluetooth_device_rssi_reported =
+                157 [(log_from_module) = "bluetooth"];
+        BluetoothDeviceFailedContactCounterReported
+                bluetooth_device_failed_contact_counter_reported = 158 [(log_from_module) = "bluetooth"];
+        BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported =
+                159 [(log_from_module) = "bluetooth"];
+        BluetoothHciTimeoutReported bluetooth_hci_timeout_reported =
+                160 [(log_from_module) = "bluetooth"];
+        BluetoothQualityReportReported bluetooth_quality_report_reported =
+                161 [(log_from_module) = "bluetooth"];
+        BluetoothDeviceInfoReported bluetooth_device_info_reported =
+                162 [(log_from_module) = "bluetooth"];
+        BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported =
+                163 [(log_from_module) = "bluetooth"];
+        BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported =
+                164 [(log_from_module) = "bluetooth"];
+        BluetoothBondStateChanged bluetooth_bond_state_changed =
+                165 [(log_from_module) = "bluetooth"];
+        BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported =
+                166 [(log_from_module) = "bluetooth"];
+        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported =
+                167 [(log_from_module) = "bluetooth"];
         ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168;
         ProcessStartTime process_start_time = 169;
         PermissionGrantRequestResultReported permission_grant_request_result_reported =
@@ -280,7 +301,8 @@
         BiometricEnrolled biometric_enrolled = 184;
         SystemServerWatchdogOccurred system_server_watchdog_occurred = 185;
         TombStoneOccurred tomb_stone_occurred = 186;
-        BluetoothClassOfDeviceReported bluetooth_class_of_device_reported = 187;
+        BluetoothClassOfDeviceReported bluetooth_class_of_device_reported =
+                187 [(log_from_module) = "bluetooth"];
         IntelligenceEventReported intelligence_event_reported =
             188 [(log_from_module) = "intelligence"];
         ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2e14446..86b2c06 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -356,11 +356,9 @@
         registerService(Context.TETHERING_SERVICE, TetheringManager.class,
                 new CachedServiceFetcher<TetheringManager>() {
             @Override
-            public TetheringManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getService(Context.TETHERING_SERVICE);
-                if (b == null) return null;
-
-                return new TetheringManager(ctx, b);
+            public TetheringManager createService(ContextImpl ctx) {
+                return new TetheringManager(
+                        ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
             }});
 
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 8415ecd..b6d096c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2162,6 +2162,33 @@
     }
 
     /**
+     * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
+     * were connected with most recently first and least recently last
+     *
+     * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
+     * connected
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+        if (getState() != STATE_ON) {
+            return new ArrayList<>();
+        }
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                return mService.getMostRecentlyConnectedDevices();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        return new ArrayList<>();
+    }
+
+    /**
      * Return the set of {@link BluetoothDevice} objects that are bonded
      * (paired) to the local adapter.
      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
index 35e0f88..1403bba 100644
--- a/packages/Tethering/common/TetheringLib/jarjar-rules.txt
+++ b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
@@ -1 +1,2 @@
 rule android.annotation.** com.android.networkstack.tethering.annotation.@1
+rule com.android.internal.annotations.** com.android.networkstack.tethering.annotation.@1
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 37ce1d57..53a358f 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -30,6 +30,9 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -37,6 +40,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.function.Supplier;
 
 /**
  * This class provides the APIs to control the tethering service.
@@ -50,17 +54,23 @@
 public class TetheringManager {
     private static final String TAG = TetheringManager.class.getSimpleName();
     private static final int DEFAULT_TIMEOUT_MS = 60_000;
+    private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
 
-    private static TetheringManager sInstance;
+    @GuardedBy("mConnectorWaitQueue")
+    @Nullable
+    private ITetheringConnector mConnector;
+    @GuardedBy("mConnectorWaitQueue")
+    @NonNull
+    private final List<ConnectorConsumer> mConnectorWaitQueue = new ArrayList<>();
+    private final Supplier<IBinder> mConnectorSupplier;
 
-    private final ITetheringConnector mConnector;
     private final TetheringCallbackInternal mCallback;
     private final Context mContext;
     private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
             mTetheringEventCallbacks = new ArrayMap<>();
 
-    private TetheringConfigurationParcel mTetheringConfiguration;
-    private TetherStatesParcel mTetherStatesParcel;
+    private volatile TetheringConfigurationParcel mTetheringConfiguration;
+    private volatile TetherStatesParcel mTetherStatesParcel;
 
     /**
      * Broadcast Action: A tetherable connection has come or gone.
@@ -162,29 +172,139 @@
     /**
      * Create a TetheringManager object for interacting with the tethering service.
      *
+     * @param context Context for the manager.
+     * @param connectorSupplier Supplier for the manager connector; may return null while the
+     *                          service is not connected.
      * {@hide}
      */
-    public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
+    public TetheringManager(@NonNull final Context context,
+            @NonNull Supplier<IBinder> connectorSupplier) {
         mContext = context;
-        mConnector = ITetheringConnector.Stub.asInterface(service);
         mCallback = new TetheringCallbackInternal();
+        mConnectorSupplier = connectorSupplier;
 
         final String pkgName = mContext.getOpPackageName();
+
+        final IBinder connector = mConnectorSupplier.get();
+        // If the connector is available on start, do not start a polling thread. This introduces
+        // differences in the thread that sends the oneway binder calls to the service between the
+        // first few seconds after boot and later, but it avoids always having differences between
+        // the first usage of TetheringManager from a process and subsequent usages (so the
+        // difference is only on boot). On boot binder calls may be queued until the service comes
+        // up and be sent from a worker thread; later, they are always sent from the caller thread.
+        // Considering that it's just oneway binder calls, and ordering is preserved, this seems
+        // better than inconsistent behavior persisting after boot.
+        if (connector != null) {
+            mConnector = ITetheringConnector.Stub.asInterface(connector);
+        } else {
+            startPollingForConnector();
+        }
+
         Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
+        getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
+    }
+
+    private void startPollingForConnector() {
+        new Thread(() -> {
+            while (true) {
+                try {
+                    Thread.sleep(200);
+                } catch (InterruptedException e) {
+                    // Not much to do here, the system needs to wait for the connector
+                }
+
+                final IBinder connector = mConnectorSupplier.get();
+                if (connector != null) {
+                    onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
+                    return;
+                }
+            }
+        }).start();
+    }
+
+    private interface ConnectorConsumer {
+        void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
+    }
+
+    private void onTetheringConnected(ITetheringConnector connector) {
+        // Process the connector wait queue in order, including any items that are added
+        // while processing.
+        //
+        // 1. Copy the queue to a local variable under lock.
+        // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
+        //    would block on the lock).
+        // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
+        //    If not, set mConnector to non-null so future tasks are run immediately, not queued.
+        //
+        // For this to work, all calls to the tethering service must use getConnector(), which
+        // ensures that tasks are added to the queue with the lock held.
+        //
+        // Once mConnector is set to non-null, it will never be null again. If the network stack
+        // process crashes, no recovery is possible.
+        // TODO: evaluate whether it is possible to recover from network stack process crashes
+        // (though in most cases the system will have crashed when the network stack process
+        // crashes).
+        do {
+            final List<ConnectorConsumer> localWaitQueue;
+            synchronized (mConnectorWaitQueue) {
+                localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
+                mConnectorWaitQueue.clear();
+            }
+
+            // Allow more tasks to be added at the end without blocking while draining the queue.
+            for (ConnectorConsumer task : localWaitQueue) {
+                try {
+                    task.onConnectorAvailable(connector);
+                } catch (RemoteException e) {
+                    // Most likely the network stack process crashed, which is likely to crash the
+                    // system. Keep processing other requests but report the error loudly.
+                    Log.wtf(TAG, "Error processing request for the tethering connector", e);
+                }
+            }
+
+            synchronized (mConnectorWaitQueue) {
+                if (mConnectorWaitQueue.size() == 0) {
+                    mConnector = connector;
+                    return;
+                }
+            }
+        } while (true);
+    }
+
+    /**
+     * Asynchronously get the ITetheringConnector to execute some operation.
+     *
+     * <p>If the connector is already available, the operation will be executed on the caller's
+     * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
+     * limited to performing oneway binder calls to minimize differences due to threading.
+     */
+    private void getConnector(ConnectorConsumer consumer) {
+        final ITetheringConnector connector;
+        synchronized (mConnectorWaitQueue) {
+            connector = mConnector;
+            if (connector == null) {
+                mConnectorWaitQueue.add(consumer);
+                return;
+            }
+        }
+
         try {
-            mConnector.registerTetheringEventCallback(mCallback, pkgName);
+            consumer.onConnectorAvailable(connector);
         } catch (RemoteException e) {
             throw new IllegalStateException(e);
         }
     }
 
     private interface RequestHelper {
-        void runRequest(IIntResultListener listener);
+        void runRequest(ITetheringConnector connector, IIntResultListener listener);
     }
 
+    // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
+    // return results and perform operations synchronously.
+    // TODO: remove once there are no callers of these legacy methods.
     private class RequestDispatcher {
         private final ConditionVariable mWaiting;
-        public int mRemoteResult;
+        public volatile int mRemoteResult;
 
         private final IIntResultListener mListener = new IIntResultListener.Stub() {
                 @Override
@@ -199,7 +319,7 @@
         }
 
         int waitForResult(final RequestHelper request) {
-            request.runRequest(mListener);
+            getConnector(c -> request.runRequest(c, mListener));
             if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
                 throw new IllegalStateException("Callback timeout");
             }
@@ -222,7 +342,7 @@
     }
 
     private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
-        private int mError = TETHER_ERROR_NO_ERROR;
+        private volatile int mError = TETHER_ERROR_NO_ERROR;
         private final ConditionVariable mWaitForCallback = new ConditionVariable();
 
         @Override
@@ -280,9 +400,9 @@
         Log.i(TAG, "tether caller:" + callerPkg);
         final RequestDispatcher dispatcher = new RequestDispatcher();
 
-        return dispatcher.waitForResult(listener -> {
+        return dispatcher.waitForResult((connector, listener) -> {
             try {
-                mConnector.tether(iface, callerPkg, listener);
+                connector.tether(iface, callerPkg, listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -304,9 +424,9 @@
 
         final RequestDispatcher dispatcher = new RequestDispatcher();
 
-        return dispatcher.waitForResult(listener -> {
+        return dispatcher.waitForResult((connector, listener) -> {
             try {
-                mConnector.untether(iface, callerPkg, listener);
+                connector.untether(iface, callerPkg, listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -330,9 +450,9 @@
 
         final RequestDispatcher dispatcher = new RequestDispatcher();
 
-        return dispatcher.waitForResult(listener -> {
+        return dispatcher.waitForResult((connector, listener) -> {
             try {
-                mConnector.setUsbTethering(enable, callerPkg, listener);
+                connector.setUsbTethering(enable, callerPkg, listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -467,11 +587,7 @@
                 });
             }
         };
-        try {
-            mConnector.startTethering(request.getParcel(), callerPkg, listener);
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e);
-        }
+        getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
     }
 
     /**
@@ -509,15 +625,15 @@
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopTethering caller:" + callerPkg);
 
-        final RequestDispatcher dispatcher = new RequestDispatcher();
-
-        dispatcher.waitForResult(listener -> {
-            try {
-                mConnector.stopTethering(type, callerPkg, listener);
-            } catch (RemoteException e) {
-                throw new IllegalStateException(e);
+        getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
+            @Override
+            public void onResult(int resultCode) {
+                // TODO: provide an API to obtain result
+                // This has never been possible as stopTethering has always been void and never
+                // taken a callback object. The only indication that callers have is if the call
+                // results in a TETHER_STATE_CHANGE broadcast.
             }
-        });
+        }));
     }
 
     /**
@@ -591,12 +707,8 @@
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
 
-        try {
-            mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi,
-                    callerPkg);
-        } catch (RemoteException e) {
-            throw new IllegalStateException(e);
-        }
+        getConnector(c -> c.requestLatestTetheringEntitlementResult(
+                type, receiver, showEntitlementUi, callerPkg));
     }
 
     /**
@@ -832,11 +944,7 @@
                     });
                 }
             };
-            try {
-                mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
-            } catch (RemoteException e) {
-                throw new IllegalStateException(e);
-            }
+            getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
             mTetheringEventCallbacks.put(callback, remoteCallback);
         }
     }
@@ -860,11 +968,8 @@
             if (remoteCallback == null) {
                 throw new IllegalArgumentException("callback was not registered.");
             }
-            try {
-                mConnector.unregisterTetheringEventCallback(remoteCallback, callerPkg);
-            } catch (RemoteException e) {
-                throw new IllegalStateException(e);
-            }
+
+            getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
         }
     }
 
@@ -1002,9 +1107,9 @@
         final String callerPkg = mContext.getOpPackageName();
 
         final RequestDispatcher dispatcher = new RequestDispatcher();
-        final int ret = dispatcher.waitForResult(listener -> {
+        final int ret = dispatcher.waitForResult((connector, listener) -> {
             try {
-                mConnector.isTetheringSupported(callerPkg, listener);
+                connector.isTetheringSupported(callerPkg, listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -1027,13 +1132,14 @@
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopAllTethering caller:" + callerPkg);
 
-        final RequestDispatcher dispatcher = new RequestDispatcher();
-        dispatcher.waitForResult(listener -> {
-            try {
-                mConnector.stopAllTethering(callerPkg, listener);
-            } catch (RemoteException e) {
-                throw new IllegalStateException(e);
+        getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
+            @Override
+            public void onResult(int resultCode) {
+                // TODO: add an API parameter to send result to caller.
+                // This has never been possible as stopAllTethering has always been void and never
+                // taken a callback object. The only indication that callers have is if the call
+                // results in a TETHER_STATE_CHANGE broadcast.
             }
-        });
+        }));
     }
 }
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index fa55601..75deb01 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -434,7 +434,7 @@
     AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
     vector<java_type_t> nonChainedSignature;
     if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        auto it = atoms->non_chained_signatures_to_modules.find(signature);
+        auto it = atoms->non_chained_signatures_to_modules.find(nonChainedSignature);
         if (it == atoms->non_chained_signatures_to_modules.end()) {
             set<string> modules_non_chained;
             if (atomDecl.hasModule) {
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index fef490c..c29936b 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -73,7 +73,7 @@
                         java_type_name(chainField.javaType), chainField.name.c_str());
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                fprintf(out, ", SparseArray<Object> valueMap");
+                fprintf(out, ", android.util.SparseArray<Object> valueMap");
             } else {
                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
             }
@@ -85,8 +85,9 @@
         string indent("");
         if (supportQ) {
             // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
-            fprintf(out, "        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n");
-            fprintf(out, "                Build.VERSION.CODENAME.equals(\"R\")) {\n");
+            fprintf(out, "        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
+            fprintf(out, "                || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+            fprintf(out, "                    && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
             indent = "    ";
         }
 
@@ -141,16 +142,16 @@
                 fprintf(out,
                         "%s        final int count = valueMap.size();\n", indent.c_str());
                 fprintf(out,
-                        "%s        final SparseIntArray intMap = new SparseIntArray();\n",
+                        "%s        android.util.SparseIntArray intMap = null;\n",
                         indent.c_str());
                 fprintf(out,
-                        "%s        final SparseLongArray longMap = new SparseLongArray();\n",
+                        "%s        android.util.SparseLongArray longMap = null;\n",
                         indent.c_str());
                 fprintf(out,
-                        "%s        final SparseArray<String> stringMap = new SparseArray<>();\n",
+                        "%s        android.util.SparseArray<String> stringMap = null;\n",
                         indent.c_str());
                 fprintf(out,
-                        "%s        final SparseArray<Float> floatMap = new SparseArray<>();\n",
+                        "%s        android.util.SparseArray<Float> floatMap = null;\n",
                         indent.c_str());
                 fprintf(out,
                         "%s        for (int i = 0; i < count; i++) {\n", indent.c_str());
@@ -162,18 +163,42 @@
                 fprintf(out,
                         "%s            if (value instanceof Integer) {\n", indent.c_str());
                 fprintf(out,
+                        "%s                if (null == intMap) {\n", indent.c_str());
+                fprintf(out,
+                        "%s                    intMap = new android.util.SparseIntArray();\n", indent.c_str());
+                fprintf(out,
+                        "%s                }\n", indent.c_str());
+                fprintf(out,
                         "%s                intMap.put(key, (Integer) value);\n", indent.c_str());
                 fprintf(out,
                         "%s            } else if (value instanceof Long) {\n", indent.c_str());
                 fprintf(out,
+                        "%s                if (null == longMap) {\n", indent.c_str());
+                fprintf(out,
+                        "%s                    longMap = new android.util.SparseLongArray();\n", indent.c_str());
+                fprintf(out,
+                        "%s                }\n", indent.c_str());
+                fprintf(out,
                         "%s                longMap.put(key, (Long) value);\n", indent.c_str());
                 fprintf(out,
                         "%s            } else if (value instanceof String) {\n", indent.c_str());
                 fprintf(out,
+                        "%s                if (null == stringMap) {\n", indent.c_str());
+                fprintf(out,
+                        "%s                    stringMap = new android.util.SparseArray<>();\n", indent.c_str());
+                fprintf(out,
+                        "%s                }\n", indent.c_str());
+                fprintf(out,
                         "%s                stringMap.put(key, (String) value);\n", indent.c_str());
                 fprintf(out,
                         "%s            } else if (value instanceof Float) {\n", indent.c_str());
                 fprintf(out,
+                        "%s                if (null == floatMap) {\n", indent.c_str());
+                fprintf(out,
+                        "%s                    floatMap = new android.util.SparseArray<>();\n", indent.c_str());
+                fprintf(out,
+                        "%s                }\n", indent.c_str());
+                fprintf(out,
                         "%s                floatMap.put(key, (Float) value);\n", indent.c_str());
                 fprintf(out,
                         "%s            }\n", indent.c_str());
@@ -228,7 +253,8 @@
 
 int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
                                     const string& moduleName, const string& javaClass,
-                                    const string& javaPackage, const bool supportQ) {
+                                    const string& javaPackage, const bool supportQ,
+                                    const bool supportWorkSource) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -240,25 +266,9 @@
         fprintf(out, "import android.os.SystemClock;\n");
     }
 
-    if (DEFAULT_MODULE_NAME == moduleName) {
-        // Mainline modules don't use WorkSource logging.
-        fprintf(out, "import android.os.WorkSource;\n");
-
-        // SparseArray is used for writing KeyValuePairs; not supported for Mainline modules.
-        fprintf(out, "import android.util.SparseArray;\n");
-        fprintf(out, "import android.util.SparseIntArray;\n");
-        fprintf(out, "import android.util.SparseLongArray;\n");
-    }
-
     fprintf(out, "import android.util.StatsEvent;\n");
     fprintf(out, "import android.util.StatsLog;\n");
 
-    if (DEFAULT_MODULE_NAME == moduleName) {
-        // List is used for WorkSource writing. Only needed for default module.
-        fprintf(out, "\n");
-        fprintf(out, "import java.util.ArrayList;\n");
-    }
-
     fprintf(out, "\n");
     fprintf(out, "\n");
     fprintf(out, "/**\n");
@@ -280,7 +290,7 @@
             out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ);
     errors += write_java_non_chained_methods(
             out, atoms.non_chained_signatures_to_modules, moduleName);
-    if (DEFAULT_MODULE_NAME == moduleName) {
+    if (supportWorkSource) {
         errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
     }
 
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 9324b23..5b78f05 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -31,8 +31,9 @@
 using namespace std;
 
 int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                                    const string& moduleName, const string& javaClass,
-                                    const string& javaPackage, const bool supportQ);
+                         const string& moduleName, const string& javaClass,
+                         const string& javaPackage, const bool supportQ,
+                         const bool supportWorkSource);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index d6899f6..f866129 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -382,7 +382,7 @@
                         java_type_name(chainField.javaType), chainField.name.c_str());
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-                fprintf(out, ", SparseArray<Object> value_map");
+                fprintf(out, ", android.util.SparseArray<Object> value_map");
             } else {
                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
             }
@@ -393,16 +393,13 @@
     }
 }
 
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) {
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+                           const bool supportWorkSource) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
     fprintf(out, "package android.util;\n");
     fprintf(out, "\n");
-    fprintf(out, "import android.os.WorkSource;\n");
-    fprintf(out, "import android.util.SparseArray;\n");
-    fprintf(out, "import java.util.ArrayList;\n");
-    fprintf(out, "\n");
     fprintf(out, "\n");
     fprintf(out, "/**\n");
     fprintf(out, " * API For logging statistics events.\n");
@@ -418,16 +415,19 @@
     write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
     write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
             attributionDecl);
-    write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
+    if (supportWorkSource) {
+        write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
+    }
 
     fprintf(out, "}\n");
 
     return 0;
 }
 
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                                    const string& moduleName, const string& javaClass,
-                                    const string& javaPackage) {
+int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
+                                      const AtomDecl &attributionDecl, const string& moduleName,
+                                      const string& javaClass, const string& javaPackage,
+                                      const bool supportWorkSource) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -438,8 +438,6 @@
     fprintf(out, "import android.util.StatsLog;\n");
     fprintf(out, "import android.os.SystemClock;\n");
     fprintf(out, "\n");
-    fprintf(out, "import java.util.ArrayList;\n");
-    fprintf(out, "\n");
     fprintf(out, "\n");
     fprintf(out, "/**\n");
     fprintf(out, " * Utility class for logging statistics events.\n");
@@ -459,6 +457,9 @@
             moduleName, "    ");
     errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
             moduleName);
+    if (supportWorkSource) {
+        errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
+    }
 
     fprintf(out, "}\n");
 
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 96ac745..36df1d8 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -46,11 +46,12 @@
         const string& indent);
 
 #if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl);
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+                           const bool supportWorkSource);
 
 int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
         const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
-        const string& javaPackage);
+        const string& javaPackage, const bool supportWorkSource);
 #endif
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 00a3704..6089532 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -512,6 +512,7 @@
     fprintf(stderr, "                       Optional for Java with module.\n");
     fprintf(stderr, "                       Default is \"StatsLogInternal\"\n");
     fprintf(stderr, "  --supportQ           Include support for Android Q.\n");
+    fprintf(stderr, "  --worksource         Include support for logging WorkSource objects.\n");
 }
 
 /**
@@ -534,6 +535,7 @@
     string javaPackage = DEFAULT_JAVA_PACKAGE;
     string javaClass = DEFAULT_JAVA_CLASS;
     bool supportQ = false;
+    bool supportWorkSource = false;
 
     int index = 1;
     while (index < argc) {
@@ -626,6 +628,8 @@
             atomsInfoCppHeaderImport = argv[index];
         } else if (0 == strcmp("--supportQ", argv[index])) {
             supportQ = true;
+        } else if (0 == strcmp("--worksource", argv[index])) {
+            supportWorkSource = true;
         }
 
         index++;
@@ -728,19 +732,15 @@
             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
             return 1;
         }
-        // If this is for a specific module, the java package must also be provided.
-        if (moduleName != DEFAULT_MODULE_NAME && javaPackage== DEFAULT_JAVA_PACKAGE) {
-            fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n");
-            return 1;
-        }
 
 #if defined(STATS_SCHEMA_LEGACY)
         if (moduleName == DEFAULT_MODULE_NAME) {
             errorCount = android::stats_log_api_gen::write_stats_log_java_q(
-                    out, atoms, attributionDecl);
+                    out, atoms, attributionDecl, supportWorkSource);
         } else {
             errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
-                    out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
+                    out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
+                    supportWorkSource);
 
         }
 #else
@@ -749,7 +749,8 @@
             javaPackage = "android.util";
         }
         errorCount = android::stats_log_api_gen::write_stats_log_java(
-                out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ);
+                out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
+                supportWorkSource);
 #endif
 
         fclose(out);
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 5b830ee..6414042 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -334,7 +334,7 @@
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
             fprintf(out, ", android.os.WorkSource workSource");
         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
-            fprintf(out, ", SparseArray<Object> value_map");
+            fprintf(out, ", android.util.SparseArray<Object> value_map");
         } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
             fprintf(out, ", byte[] %s", field->name.c_str());
         } else {
@@ -442,7 +442,7 @@
         for (vector<java_type_t>::const_iterator arg = signature.begin();
                 arg != signature.end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                fprintf(out, ", WorkSource ws");
+                fprintf(out, ", android.os.WorkSource ws");
             } else {
                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
             }
@@ -464,9 +464,10 @@
         fprintf(out, "        }\n"); // close for-loop
 
         // write() component.
-        fprintf(out, "        ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
+        fprintf(out, "        java.util.ArrayList<android.os.WorkSource.WorkChain> workChains = "
+                "ws.getWorkChains();\n");
         fprintf(out, "        if (workChains != null) {\n");
-        fprintf(out, "            for (WorkSource.WorkChain wc : workChains) {\n");
+        fprintf(out, "            for (android.os.WorkSource.WorkChain wc : workChains) {\n");
         fprintf(out, "                write(code");
         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
             if (argIndex == attributionArg) {