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