Merge "adb: fix deadlock."
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..41f7b89
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+python_binary_host {
+  name: "adb_integration_test_adb",
+  main: "test_adb.py",
+  srcs: [
+    "test_adb.py",
+  ],
+  libs: [
+    "adb_py",
+  ],
+  version: {
+    py2: {
+      enabled: true,
+    },
+    py3: {
+      enabled: false,
+    },
+  },
+}
+
+python_binary_host {
+  name: "adb_integration_test_device",
+  main: "test_device.py",
+  srcs: [
+    "test_device.py",
+  ],
+  libs: [
+    "adb_py",
+  ],
+  version: {
+    py2: {
+      enabled: true,
+    },
+    py3: {
+      enabled: false,
+    },
+  },
+}
diff --git a/Android.mk b/Android.mk
index 382c8cb..1f6f194 100644
--- a/Android.mk
+++ b/Android.mk
@@ -387,4 +387,9 @@
 
 include $(BUILD_EXECUTABLE)
 
+# adb integration test
+# =========================================================
+$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_adb.BUILT))
+$(call dist-for-goals,sdk,$(ALL_MODULES.adb_integration_test_device.BUILT))
+
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/adb.cpp b/adb.cpp
index 808d8ff..a7706a0 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -1140,6 +1140,7 @@
         if (should_use_libusb()) {
             features.insert(kFeatureLibusb);
         }
+        features.insert(kFeaturePushSync);
         SendOkay(reply_fd, FeatureSetToString(features));
         return 0;
     }
diff --git a/bugreport.cpp b/bugreport.cpp
index d0cc072..372a3b4 100644
--- a/bugreport.cpp
+++ b/bugreport.cpp
@@ -149,7 +149,7 @@
             int progress = std::stoi(line.substr(idx1, (idx2 - idx1)));
             int total = std::stoi(line.substr(idx2 + 1));
             int progress_percentage = (progress * 100 / total);
-            if (progress_percentage <= last_progress_percentage_) {
+            if (progress_percentage != 0 && progress_percentage <= last_progress_percentage_) {
                 // Ignore.
                 return;
             }
diff --git a/bugreport_test.cpp b/bugreport_test.cpp
index 2b368d7..d3787b4 100644
--- a/bugreport_test.cpp
+++ b/bugreport_test.cpp
@@ -311,6 +311,29 @@
     ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
 }
 
+// Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0%
+TEST_F(BugreportTest, OkProgressZeroPercentIsNotIgnored) {
+    ExpectBugreportzVersion("1.1");
+    ExpectProgress(0);
+    ExpectProgress(1);
+    // clang-format off
+    EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
+        // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
+        .WillOnce(DoAll(
+            WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
+            WithArg<4>(WriteOnStdout("PROGRESS:1/100000\n")),
+            WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
+            WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
+            WithArg<4>(ReturnCallbackDone())));
+    // clang-format on
+    EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
+                                true, StrEq("pulling file.zip")))
+        .WillOnce(Return(true));
+
+    const char* args[] = {"bugreport", "file.zip"};
+    ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
+}
+
 // Tests 'adb bugreport dir' when it succeeds and destination is a directory.
 TEST_F(BugreportTest, OkDirectory) {
     ExpectBugreportzVersion("1.1");
diff --git a/transport.cpp b/transport.cpp
index 24e90cf..308ee8d 100644
--- a/transport.cpp
+++ b/transport.cpp
@@ -55,6 +55,7 @@
 const char* const kFeatureCmd = "cmd";
 const char* const kFeatureStat2 = "stat_v2";
 const char* const kFeatureLibusb = "libusb";
+const char* const kFeaturePushSync = "push_sync";
 
 static std::string dump_packet(const char* name, const char* func, apacket* p) {
     unsigned command = p->msg.command;
diff --git a/transport.h b/transport.h
index 7304404..57fc988 100644
--- a/transport.h
+++ b/transport.h
@@ -51,6 +51,8 @@
 extern const char* const kFeatureStat2;
 // The server is running with libusb enabled.
 extern const char* const kFeatureLibusb;
+// The server supports `push --sync`.
+extern const char* const kFeaturePushSync;
 
 class atransport {
 public: