Merge "Installd: Add move_ab command" into nyc-dev
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
new file mode 100644
index 0000000..674c163
--- /dev/null
+++ b/aidl/gui/android/view/Surface.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/view/Surface.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.view;
+
+parcelable Surface cpp_header "gui/Surface.h";
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
index 9be0901..8335c14 100644
--- a/cmds/dumpsys/Android.mk
+++ b/cmds/dumpsys/Android.mk
@@ -5,10 +5,11 @@
 	dumpsys.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	libbase \
 	libutils \
 	liblog \
 	libbinder
-	
+
 
 ifeq ($(TARGET_OS),linux)
 	LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index ef009da..46fb81a 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -5,21 +5,33 @@
 
 #define LOG_TAG "dumpsys"
 
-#include <utils/Log.h>
+#include <algorithm>
+#include <chrono>
+#include <thread>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
 #include <binder/TextOutput.h>
+#include <utils/Log.h>
 #include <utils/Vector.h>
 
+#include <fcntl.h>
 #include <getopt.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 using namespace android;
+using android::base::unique_fd;
+using android::base::WriteFully;
 
 static int sort_func(const String16* lhs, const String16* rhs)
 {
@@ -121,23 +133,108 @@
         return 0;
     }
 
-    for (size_t i=0; i<N; i++) {
-        if (IsSkipped(skippedServices, services[i])) continue;
+    for (size_t i = 0; i < N; i++) {
+        String16 service_name = std::move(services[i]);
+        if (IsSkipped(skippedServices, service_name)) continue;
 
-        sp<IBinder> service = sm->checkService(services[i]);
+        sp<IBinder> service = sm->checkService(service_name);
         if (service != NULL) {
+            int sfd[2];
+
+            // Use a socketpair instead of a pipe to avoid sending SIGPIPE to services that timeout.
+            if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) != 0) {
+                aerr << "Failed to create socketpair to dump service info for " << service_name
+                     << ": " << strerror(errno) << endl;
+                continue;
+            }
+
+            unique_fd local_end(sfd[0]);
+            unique_fd remote_end(sfd[1]);
+            sfd[0] = sfd[1] = -1;
+
             if (N > 1) {
                 aout << "------------------------------------------------------------"
                         "-------------------" << endl;
-                aout << "DUMP OF SERVICE " << services[i] << ":" << endl;
+                aout << "DUMP OF SERVICE " << service_name << ":" << endl;
             }
-            int err = service->dump(STDOUT_FILENO, args);
-            if (err != 0) {
-                aerr << "Error dumping service info: (" << strerror(err)
-                        << ") " << services[i] << endl;
+
+            // dump blocks until completion, so spawn a thread..
+            std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
+                int err = service->dump(remote_end.get(), args);
+
+                // It'd be nice to be able to close the remote end of the socketpair before the dump
+                // call returns, to terminate our reads if the other end closes their copy of the
+                // file descriptor, but then hangs for some reason. There doesn't seem to be a good
+                // way to do this, though.
+                remote_end.clear();
+
+                if (err != 0) {
+                    aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
+                         << endl;
+                }
+            });
+
+            // TODO: Make this configurable at runtime.
+            constexpr auto timeout = std::chrono::seconds(10);
+            auto end = std::chrono::steady_clock::now() + timeout;
+
+            struct pollfd pfd = {
+                .fd = local_end.get(),
+                .events = POLLIN
+            };
+
+            bool timed_out = false;
+            bool error = false;
+            while (true) {
+                // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
+                auto time_left_ms = [end]() {
+                    auto now = std::chrono::steady_clock::now();
+                    auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+                    return std::max(diff.count(), 0ll);
+                };
+
+                int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+                if (rc < 0) {
+                    aerr << "Error in poll while dumping service " << service_name << " : "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                } else if (rc == 0) {
+                    timed_out = true;
+                    break;
+                }
+
+                char buf[4096];
+                rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
+                if (rc < 0) {
+                    aerr << "Failed to read while dumping service " << service_name << ": "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                } else if (rc == 0) {
+                    // EOF.
+                    break;
+                }
+
+                if (!WriteFully(STDOUT_FILENO, buf, rc)) {
+                    aerr << "Failed to write while dumping service " << service_name << ": "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                }
+            }
+
+            if (timed_out) {
+                aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
+            }
+
+            if (timed_out || error) {
+                dump_thread.detach();
+            } else {
+                dump_thread.join();
             }
         } else {
-            aerr << "Can't find service: " << services[i] << endl;
+            aerr << "Can't find service: " << service_name << endl;
         }
     }
 
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 3afdaae..9f51cdd 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -23,6 +23,8 @@
 #include <ui/ANativeObjectBase.h>
 #include <ui/Region.h>
 
+#include <binder/Parcelable.h>
+
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
@@ -348,6 +350,43 @@
     bool mSharedBufferHasBeenQueued;
 };
 
+namespace view {
+
+/**
+ * A simple holder for an IGraphicBufferProducer, to match the managed-side
+ * android.view.Surface parcelable behavior.
+ *
+ * This implements android/view/Surface.aidl
+ *
+ * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
+ * used in managed Binder calls.
+ */
+class Surface : public Parcelable {
+  public:
+
+    String16 name;
+    sp<IGraphicBufferProducer> graphicBufferProducer;
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    // nameAlreadyWritten set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
+
+    // nameAlreadyRead set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
+
+  private:
+
+    static String16 readMaybeEmptyString16(const Parcel* parcel);
+};
+
+} // namespace view
+
 }; // namespace android
 
 #endif  // ANDROID_GUI_SURFACE_H
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c295684..8025ca5 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1259,4 +1259,57 @@
     return err;
 }
 
+namespace view {
+
+status_t Surface::writeToParcel(Parcel* parcel) const {
+    return writeToParcel(parcel, false);
+}
+
+status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    status_t res = OK;
+
+    if (!nameAlreadyWritten) res = parcel->writeString16(name);
+
+    if (res == OK) {
+        res = parcel->writeStrongBinder(
+                IGraphicBufferProducer::asBinder(graphicBufferProducer));
+    }
+    return res;
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel) {
+    return readFromParcel(parcel, false);
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    if (!nameAlreadyRead) {
+        name = readMaybeEmptyString16(parcel);
+    }
+
+    sp<IBinder> binder;
+
+    status_t res = parcel->readStrongBinder(&binder);
+    if (res != OK) return res;
+
+    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
+
+    return OK;
+}
+
+String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
+    size_t len;
+    const char16_t* str = parcel->readString16Inplace(&len);
+    if (str != nullptr) {
+        return String16(str, len);
+    } else {
+        return String16();
+    }
+}
+
+} // namespace view
+
 }; // namespace android