adb: Add a way to reconnect TCP transports

This change adds a reconnect handler that tracks all TCP transports that
were connected at some point, but became disconnected. It does so by
attempting to reconnect every 10s for up to a minute.

Bug: 74411879
Test: system/core/adb/test_adb.py
Test: adb connect chromebook:22  # This runs with sslh
Test: CtsBootStatsTestCases
Test: emulator -show-kernel ; adb -s emulator-5554 shell

Change-Id: I7b9f6d181b71ccf5c26ff96c45d36aaf6409b992
diff --git a/adb/transport.h b/adb/transport.h
index e1cbc09..ae9cc02 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -198,20 +198,27 @@
     // class in one go is a very large change. Given how bad our testing is,
     // it's better to do this piece by piece.
 
-    atransport(ConnectionState state = kCsConnecting)
+    using ReconnectCallback = std::function<bool(atransport*)>;
+
+    atransport(ReconnectCallback reconnect, ConnectionState state)
         : id(NextTransportId()),
+          kicked_(false),
           connection_state_(state),
           connection_waitable_(std::make_shared<ConnectionWaitable>()),
-          connection_(nullptr) {
+          connection_(nullptr),
+          reconnect_(std::move(reconnect)) {
         // Initialize protocol to min version for compatibility with older versions.
         // Version will be updated post-connect.
         protocol_version = A_VERSION_MIN;
         max_payload = MAX_PAYLOAD;
     }
+    atransport(ConnectionState state = kCsOffline)
+        : atransport([](atransport*) { return false; }, state) {}
     virtual ~atransport();
 
     int Write(apacket* p);
     void Kick();
+    bool kicked() const { return kicked_; }
 
     // ConnectionState can be read by all threads, but can only be written in the main thread.
     ConnectionState GetConnectionState() const;
@@ -286,8 +293,12 @@
     // Gets a shared reference to the ConnectionWaitable.
     std::shared_ptr<ConnectionWaitable> connection_waitable() { return connection_waitable_; }
 
+    // Attempts to reconnect with the underlying Connection. Returns true if the
+    // reconnection attempt succeeded.
+    bool Reconnect();
+
   private:
-    bool kicked_ = false;
+    std::atomic<bool> kicked_;
 
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -310,6 +321,9 @@
     // The underlying connection object.
     std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
 
+    // A callback that will be invoked when the atransport needs to reconnect.
+    ReconnectCallback reconnect_;
+
     std::mutex mutex_;
 
     DISALLOW_COPY_AND_ASSIGN(atransport);
@@ -333,6 +347,7 @@
 // Stops iteration and returns false if fn returns false, otherwise returns true.
 bool iterate_transports(std::function<bool(const atransport*)> fn);
 
+void init_reconnect_handler(void);
 void init_transport_registration(void);
 void init_mdns_transport_discovery(void);
 std::string list_transports(bool long_listing);
@@ -347,7 +362,8 @@
 void connect_device(const std::string& address, std::string* response);
 
 /* cause new transports to be init'd and added to the list */
-int register_socket_transport(int s, const char* serial, int port, int local);
+int register_socket_transport(int s, const char* serial, int port, int local,
+                              atransport::ReconnectCallback reconnect);
 
 // This should only be used for transports with connection_state == kCsNoPerm.
 void unregister_usb_transport(usb_handle* usb);