summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:33:55 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:33:55 +0000
commit4417ee0aa329fbbbf02c2b5abe7702bf5e62a806 (patch)
treea6e0adff82498f3df0a2edc6722b67ddf6960def
parent3d0c616651ffdd82e9482ccce0f559e24ead4128 (diff)
parentb811c3c71002c994914dfcd2ef1fe50a5ae8b075 (diff)
downloadnative-4417ee0aa329fbbbf02c2b5abe7702bf5e62a806.tar.gz
Snap for 6001391 from b811c3c71002c994914dfcd2ef1fe50a5ae8b075 to qt-aml-networking-release
Change-Id: Ic8be587e8e2cf43ec4191c84a0d8cd6a085479c2
-rw-r--r--Android.bp1
-rw-r--r--cmds/installd/migrate_legacy_obb_data.sh10
-rw-r--r--headers/media_plugin/media/cas/CasAPI.h14
-rw-r--r--libs/adbd_auth/Android.bp44
-rw-r--r--libs/adbd_auth/adbd_auth.cpp443
-rw-r--r--libs/adbd_auth/include/adbd_auth.h65
-rw-r--r--libs/adbd_auth/libadbd_auth.map.txt13
-rw-r--r--libs/arect/Android.bp7
-rw-r--r--libs/binder/include/binder/IServiceManager.h14
-rw-r--r--libs/binder/include/binder/ParcelFileDescriptor.h18
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_auto_utils.h11
-rw-r--r--libs/binder/tests/Android.bp7
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp13
-rw-r--r--libs/sensor/Android.bp17
-rw-r--r--libs/sensor/Sensor.cpp3
-rw-r--r--libs/ui/Android.bp23
-rw-r--r--opengl/libs/EGL/egl_platform_entries.cpp91
-rw-r--r--services/surfaceflinger/Layer.cpp40
-rw-r--r--vulkan/libvulkan/Android.bp7
-rw-r--r--vulkan/nulldrv/Android.bp9
-rw-r--r--vulkan/tools/Android.bp10
21 files changed, 719 insertions, 141 deletions
diff --git a/Android.bp b/Android.bp
index bf4cf5daf8..9829c7fbad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7,6 +7,7 @@ ndk_headers {
}
subdirs = [
+ "adbd_auth",
"cmds/*",
"headers",
"libs/*",
diff --git a/cmds/installd/migrate_legacy_obb_data.sh b/cmds/installd/migrate_legacy_obb_data.sh
index 10756881be..0e6d7b9c62 100644
--- a/cmds/installd/migrate_legacy_obb_data.sh
+++ b/cmds/installd/migrate_legacy_obb_data.sh
@@ -15,17 +15,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-rm -rf /sdcard/Android/obb/test_probe
-mkdir -p /sdcard/Android/obb/
-touch /sdcard/Android/obb/test_probe
+rm -rf /data/media/Android/obb/test_probe
+mkdir -p /data/media/Android/obb/
+touch /data/media/Android/obb/test_probe
if ! test -f /data/media/0/Android/obb/test_probe ; then
log -p i -t migrate_legacy_obb_data "No support for 'unshared_obb'. Not migrating"
- rm -rf /sdcard/Android/obb/test_probe
+ rm -rf /data/media/Android/obb/test_probe
exit 0
fi
# Delete the test file, and remove the obb folder if it is empty
-rm -rf /sdcard/Android/obb/test_probe
+rm -rf /data/media/Android/obb/test_probe
rmdir /data/media/obb
if ! test -d /data/media/obb ; then
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index c87ee5655e..8cc9d365a2 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -56,6 +56,11 @@ typedef void (*CasPluginCallbackExt)(
size_t size,
const CasSessionId *sessionId);
+typedef void (*CasPluginStatusCallback)(
+ void *appData,
+ int32_t event,
+ int32_t arg);
+
struct CasFactory {
CasFactory() {}
virtual ~CasFactory() {}
@@ -91,6 +96,10 @@ struct CasPlugin {
CasPlugin() {}
virtual ~CasPlugin() {}
+ // Provide a callback to report plugin status
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) = 0;
+
// Provide the CA private data from a CA_descriptor in the conditional
// access table to a CasPlugin.
virtual status_t setPrivateData(
@@ -100,6 +109,11 @@ struct CasPlugin {
// streams.
virtual status_t openSession(CasSessionId *sessionId) = 0;
+ // Open a session with intend and mode for descrambling a program, or one
+ // or more elementary streams.
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) = 0;
+
// Close a previously opened session.
virtual status_t closeSession(const CasSessionId &sessionId) = 0;
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
new file mode 100644
index 0000000000..9cf014380c
--- /dev/null
+++ b/libs/adbd_auth/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 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.
+
+cc_library {
+ name: "libadbd_auth",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+ srcs: ["adbd_auth.cpp"],
+ export_include_dirs: ["include"],
+
+ version_script: "libadbd_auth.map.txt",
+ stubs: {
+ symbol_file: "libadbd_auth.map.txt",
+ },
+
+ host_supported: true,
+ recovery_available: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ ],
+}
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
new file mode 100644
index 0000000000..64791098ee
--- /dev/null
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION
+
+#include "include/adbd_auth.h"
+
+#include <inttypes.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/uio.h>
+
+#include <chrono>
+#include <deque>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+
+using android::base::unique_fd;
+
+struct AdbdAuthPacketAuthenticated {
+ std::string public_key;
+};
+
+struct AdbdAuthPacketDisconnected {
+ std::string public_key;
+};
+
+struct AdbdAuthPacketRequestAuthorization {
+ std::string public_key;
+};
+
+using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected,
+ AdbdAuthPacketRequestAuthorization>;
+
+struct AdbdAuthContext {
+ static constexpr uint64_t kEpollConstSocket = 0;
+ static constexpr uint64_t kEpollConstEventFd = 1;
+ static constexpr uint64_t kEpollConstFramework = 2;
+
+public:
+ explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
+ epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
+ if (epoll_fd_ == -1) {
+ PLOG(FATAL) << "failed to create epoll fd";
+ }
+
+ event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ if (event_fd_ == -1) {
+ PLOG(FATAL) << "failed to create eventfd";
+ }
+
+ sock_fd_.reset(android_get_control_socket("adbd"));
+ if (sock_fd_ == -1) {
+ PLOG(ERROR) << "failed to get adbd authentication socket";
+ } else {
+ if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) {
+ PLOG(FATAL) << "failed to make adbd authentication socket cloexec";
+ }
+
+ if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) {
+ PLOG(FATAL) << "failed to make adbd authentication socket nonblocking";
+ }
+
+ if (listen(sock_fd_.get(), 4) != 0) {
+ PLOG(FATAL) << "failed to listen on adbd authentication socket";
+ }
+ }
+ }
+
+ AdbdAuthContext(const AdbdAuthContext& copy) = delete;
+ AdbdAuthContext(AdbdAuthContext&& move) = delete;
+ AdbdAuthContext& operator=(const AdbdAuthContext& copy) = delete;
+ AdbdAuthContext& operator=(AdbdAuthContext&& move) = delete;
+
+ uint64_t NextId() { return next_id_++; }
+
+ void DispatchPendingPrompt() REQUIRES(mutex_) {
+ if (dispatched_prompt_) {
+ LOG(INFO) << "adbd_auth: prompt currently pending, skipping";
+ return;
+ }
+
+ if (pending_prompts_.empty()) {
+ LOG(INFO) << "adbd_auth: no prompts to send";
+ return;
+ }
+
+ LOG(INFO) << "adbd_auth: prompting user for adb authentication";
+ auto [id, public_key, arg] = std::move(pending_prompts_.front());
+ pending_prompts_.pop_front();
+
+ this->output_queue_.emplace_back(
+ AdbdAuthPacketRequestAuthorization{.public_key = public_key});
+
+ Interrupt();
+ dispatched_prompt_ = std::make_tuple(id, public_key, arg);
+ }
+
+ void UpdateFrameworkWritable() REQUIRES(mutex_) {
+ // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we get notified
+ // at the same time as a framework connection, but that's unlikely and this doesn't need to
+ // be fast anyway.
+ if (framework_fd_ != -1) {
+ struct epoll_event event;
+ event.events = EPOLLIN;
+ if (!output_queue_.empty()) {
+ LOG(INFO) << "marking framework writable";
+ event.events |= EPOLLOUT;
+ }
+ event.data.u64 = kEpollConstFramework;
+ CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(), &event));
+ }
+ }
+
+ void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
+ LOG(INFO) << "received new framework fd " << new_fd.get()
+ << " (current = " << framework_fd_.get() << ")";
+
+ // If we already had a framework fd, clean up after ourselves.
+ if (framework_fd_ != -1) {
+ output_queue_.clear();
+ dispatched_prompt_.reset();
+ CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(), nullptr));
+ framework_fd_.reset();
+ }
+
+ if (new_fd != -1) {
+ struct epoll_event event;
+ event.events = EPOLLIN;
+ if (!output_queue_.empty()) {
+ LOG(INFO) << "marking framework writable";
+ event.events |= EPOLLOUT;
+ }
+ event.data.u64 = kEpollConstFramework;
+ CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event));
+ framework_fd_ = std::move(new_fd);
+ }
+ }
+
+ void HandlePacket(std::string_view packet) REQUIRES(mutex_) {
+ LOG(INFO) << "received packet: " << packet;
+
+ if (packet.length() < 2) {
+ LOG(ERROR) << "received packet of invalid length";
+ ReplaceFrameworkFd(unique_fd());
+ }
+
+ if (packet[0] == 'O' && packet[1] == 'K') {
+ CHECK(this->dispatched_prompt_.has_value());
+ auto& [id, key, arg] = *this->dispatched_prompt_;
+ keys_.emplace(id, std::move(key));
+
+ this->callbacks_.key_authorized(arg, id);
+ this->dispatched_prompt_ = std::nullopt;
+ } else if (packet[0] == 'N' && packet[1] == 'O') {
+ CHECK_EQ(2UL, packet.length());
+ // TODO: Do we want a callback if the key is denied?
+ this->dispatched_prompt_ = std::nullopt;
+ DispatchPendingPrompt();
+ } else {
+ LOG(ERROR) << "unhandled packet: " << packet;
+ ReplaceFrameworkFd(unique_fd());
+ }
+ }
+
+ bool SendPacket() REQUIRES(mutex_) {
+ if (output_queue_.empty()) {
+ return false;
+ }
+
+ CHECK_NE(-1, framework_fd_.get());
+
+ auto& packet = output_queue_.front();
+ struct iovec iovs[2];
+ if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
+ iovs[0].iov_base = const_cast<char*>("CK");
+ iovs[0].iov_len = 2;
+ iovs[1].iov_base = p->public_key.data();
+ iovs[1].iov_len = p->public_key.size();
+ } else if (auto* p = std::get_if<AdbdAuthPacketDisconnected>(&packet)) {
+ iovs[0].iov_base = const_cast<char*>("DC");
+ iovs[0].iov_len = 2;
+ iovs[1].iov_base = p->public_key.data();
+ iovs[1].iov_len = p->public_key.size();
+ } else if (auto* p = std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) {
+ iovs[0].iov_base = const_cast<char*>("PK");
+ iovs[0].iov_len = 2;
+ iovs[1].iov_base = p->public_key.data();
+ iovs[1].iov_len = p->public_key.size();
+ } else {
+ LOG(FATAL) << "unhandled packet type?";
+ }
+
+ output_queue_.pop_front();
+
+ ssize_t rc = writev(framework_fd_.get(), iovs, 2);
+ if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+ PLOG(ERROR) << "failed to write to framework fd";
+ ReplaceFrameworkFd(unique_fd());
+ return false;
+ }
+
+ return true;
+ }
+
+ void Run() {
+ if (sock_fd_ == -1) {
+ LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts";
+ } else {
+ struct epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = kEpollConstSocket;
+ CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event));
+ }
+
+ {
+ struct epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = kEpollConstEventFd;
+ CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event));
+ }
+
+ while (true) {
+ struct epoll_event events[3];
+ int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
+ if (rc == -1) {
+ PLOG(FATAL) << "epoll_wait failed";
+ } else if (rc == 0) {
+ LOG(FATAL) << "epoll_wait returned 0";
+ }
+
+ bool restart = false;
+ for (int i = 0; i < rc; ++i) {
+ if (restart) {
+ break;
+ }
+
+ struct epoll_event& event = events[i];
+ switch (event.data.u64) {
+ case kEpollConstSocket: {
+ unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr,
+ SOCK_CLOEXEC | SOCK_NONBLOCK));
+ if (new_framework_fd == -1) {
+ PLOG(FATAL) << "failed to accept framework fd";
+ }
+
+ LOG(INFO) << "adbd_auth: received a new framework connection";
+ std::lock_guard<std::mutex> lock(mutex_);
+ ReplaceFrameworkFd(std::move(new_framework_fd));
+
+ // Stop iterating over events: one of the later ones might be the old
+ // framework fd.
+ restart = false;
+ break;
+ }
+
+ case kEpollConstEventFd: {
+ // We were woken up to write something.
+ uint64_t dummy;
+ int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
+ if (rc != 8) {
+ PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")";
+ }
+
+ std::lock_guard<std::mutex> lock(mutex_);
+ UpdateFrameworkWritable();
+ break;
+ }
+
+ case kEpollConstFramework: {
+ char buf[4096];
+ if (event.events & EPOLLIN) {
+ int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
+ if (rc == -1) {
+ LOG(FATAL) << "failed to read from framework fd";
+ } else if (rc == 0) {
+ LOG(INFO) << "hit EOF on framework fd";
+ std::lock_guard<std::mutex> lock(mutex_);
+ ReplaceFrameworkFd(unique_fd());
+ } else {
+ std::lock_guard<std::mutex> lock(mutex_);
+ HandlePacket(std::string_view(buf, rc));
+ }
+ }
+
+ if (event.events & EPOLLOUT) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ while (SendPacket()) {
+ continue;
+ }
+ UpdateFrameworkWritable();
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
+ void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) {
+ for (const auto& path : key_paths) {
+ if (access(path, R_OK) == 0) {
+ LOG(INFO) << "Loading keys from " << path;
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content)) {
+ PLOG(ERROR) << "Couldn't read " << path;
+ continue;
+ }
+ for (const auto& line : android::base::Split(content, "\n")) {
+ if (!callback(line.data(), line.size(), arg)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) {
+ uint64_t id = NextId();
+
+ std::lock_guard<std::mutex> lock(mutex_);
+ pending_prompts_.emplace_back(id, public_key, arg);
+ DispatchPendingPrompt();
+ return id;
+ }
+
+ uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) {
+ uint64_t id = NextId();
+ std::lock_guard<std::mutex> lock(mutex_);
+ keys_.emplace(id, public_key);
+ output_queue_.emplace_back(
+ AdbdAuthPacketDisconnected{.public_key = std::string(public_key)});
+ return id;
+ }
+
+ void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ auto it = keys_.find(id);
+ if (it == keys_.end()) {
+ LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping";
+ return;
+ }
+ output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
+ keys_.erase(it);
+ }
+
+ // Interrupt the worker thread to do some work.
+ void Interrupt() {
+ uint64_t value = 1;
+ ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
+ if (rc == -1) {
+ PLOG(FATAL) << "write to eventfd failed";
+ } else if (rc != sizeof(value)) {
+ LOG(FATAL) << "write to eventfd returned short (" << rc << ")";
+ }
+ }
+
+ unique_fd epoll_fd_;
+ unique_fd event_fd_;
+ unique_fd sock_fd_;
+ unique_fd framework_fd_;
+
+ std::atomic<uint64_t> next_id_;
+ AdbdAuthCallbacksV1 callbacks_;
+
+ std::mutex mutex_;
+ std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_);
+
+ // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
+ // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
+ std::deque<AdbdAuthPacket> output_queue_;
+
+ std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
+ std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
+};
+
+AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
+ if (callbacks->version != 1) {
+ LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
+ return nullptr;
+ }
+
+ return new AdbdAuthContext(&callbacks->callbacks.v1);
+}
+
+void adbd_auth_delete(AdbdAuthContext* ctx) {
+ delete ctx;
+}
+
+void adbd_auth_run(AdbdAuthContext* ctx) {
+ return ctx->Run();
+}
+
+void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
+ bool (*callback)(const char* public_key, size_t len, void* arg),
+ void* arg) {
+ ctx->IteratePublicKeys(callback, arg);
+}
+
+uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
+ return ctx->NotifyAuthenticated(std::string_view(public_key, len));
+}
+
+void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) {
+ return ctx->NotifyDisconnected(id);
+}
+
+void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
+ void* arg) {
+ ctx->PromptUser(std::string_view(public_key, len), arg);
+}
+
+bool adbd_auth_supports_feature(AdbdAuthFeature) {
+ return false;
+}
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
new file mode 100644
index 0000000000..b7c1cb88cc
--- /dev/null
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+extern "C" {
+
+struct AdbdAuthCallbacksV1 {
+ // Callback for a successful user authorization.
+ void (*key_authorized)(void* arg, uint64_t id);
+};
+
+struct AdbdAuthCallbacks {
+ uint32_t version;
+ union {
+ AdbdAuthCallbacksV1 v1;
+ } callbacks;
+};
+
+struct AdbdAuthContext;
+
+AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks);
+void adbd_auth_delete(AdbdAuthContext* ctx);
+
+void adbd_auth_run(AdbdAuthContext* ctx);
+
+// Iterate through the list of authorized public keys.
+// Return false from the callback to stop iteration.
+void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
+ bool (*callback)(const char* public_key, size_t len, void* arg),
+ void* arg);
+
+// Let system_server know that a key has been successfully used for authentication.
+uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len);
+
+// Let system_server know that a connection has been closed.
+void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id);
+
+// Prompt the user to authorize a public key.
+// When this happens, a callback will be run on the auth thread with the result.
+void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg);
+
+enum AdbdAuthFeature {
+};
+
+bool adbd_auth_supports_feature(AdbdAuthFeature f);
+
+}
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
new file mode 100644
index 0000000000..d01233c960
--- /dev/null
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -0,0 +1,13 @@
+LIBADBD_AUTH {
+ global:
+ adbd_auth_new; # apex
+ adbd_auth_delete; # apex
+ adbd_auth_run; # apex
+ adbd_auth_get_public_keys; #apex
+ adbd_auth_notify_auth; # apex
+ adbd_auth_notify_disconnect; # apex
+ adbd_auth_prompt_user; # apex
+ adbd_auth_supports_feature; # apex
+ local:
+ *;
+};
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index ad8287c203..2518b1427d 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -13,13 +13,18 @@
// limitations under the License.
ndk_headers {
- name: "libarect_headers",
+ name: "libarect_headers_for_ndk",
from: "include/android",
to: "android",
srcs: ["include/android/*.h"],
license: "NOTICE",
}
+cc_library_headers {
+ name: "libarect_headers",
+ export_include_dirs: ["include"],
+}
+
cc_library_static {
name: "libarect",
host_supported: true,
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index bd77567290..2c4326393e 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -113,6 +113,13 @@ sp<INTERFACE> waitForDeclaredService(const String16& name) {
return interface_cast<INTERFACE>(sm->waitForService(name));
}
+template <typename INTERFACE>
+sp<INTERFACE> checkDeclaredService(const String16& name) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (!sm->isDeclared(name)) return nullptr;
+ return interface_cast<INTERFACE>(sm->checkService(name));
+}
+
template<typename INTERFACE>
sp<INTERFACE> waitForVintfService(
const String16& instance = String16("default")) {
@@ -121,6 +128,13 @@ sp<INTERFACE> waitForVintfService(
}
template<typename INTERFACE>
+sp<INTERFACE> checkVintfService(
+ const String16& instance = String16("default")) {
+ return checkDeclaredService<INTERFACE>(
+ INTERFACE::descriptor + String16("/") + instance);
+}
+
+template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 662e56e864..4635ad84c6 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -42,6 +42,24 @@ public:
android::status_t writeToParcel(android::Parcel* parcel) const override;
android::status_t readFromParcel(const android::Parcel* parcel) override;
+ inline bool operator!=(const ParcelFileDescriptor& rhs) const {
+ return mFd != rhs.mFd;
+ }
+ inline bool operator<(const ParcelFileDescriptor& rhs) const {
+ return mFd < rhs.mFd;
+ }
+ inline bool operator<=(const ParcelFileDescriptor& rhs) const {
+ return mFd <= rhs.mFd;
+ }
+ inline bool operator==(const ParcelFileDescriptor& rhs) const {
+ return mFd == rhs.mFd;
+ }
+ inline bool operator>(const ParcelFileDescriptor& rhs) const {
+ return mFd > rhs.mFd;
+ }
+ inline bool operator>=(const ParcelFileDescriptor& rhs) const {
+ return mFd >= rhs.mFd;
+ }
private:
android::base::unique_fd mFd;
};
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index 8f37c5e3d3..946ccb79a5 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -159,13 +159,17 @@ class ScopedAResource {
*/
T* getR() { return &mT; }
- // copy-constructing, or move/copy assignment is disallowed
+ // copy-constructing/assignment is disallowed
ScopedAResource(const ScopedAResource&) = delete;
ScopedAResource& operator=(const ScopedAResource&) = delete;
- ScopedAResource& operator=(ScopedAResource&&) = delete;
- // move-constructing is okay
+ // move-constructing/assignment is okay
ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; }
+ ScopedAResource& operator=(ScopedAResource&& other) {
+ set(other.mT);
+ other.mT = DEFAULT;
+ return *this;
+ }
private:
T mT;
@@ -197,6 +201,7 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delet
explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
~ScopedAStatus() {}
ScopedAStatus(ScopedAStatus&&) = default;
+ ScopedAStatus& operator=(ScopedAStatus&&) = default;
/**
* See AStatus_isOk.
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 635ea69fb4..5a7f9a97fa 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -119,12 +119,7 @@ cc_test {
srcs: ["binderSafeInterfaceTest.cpp"],
cppflags: [
- "-Weverything",
- "-Wno-c++98-compat",
- "-Wno-c++98-compat-pedantic",
- "-Wno-global-constructors",
- "-Wno-padded",
- "-Wno-weak-vtables",
+ "-Wextra",
],
cpp_std: "experimental",
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 05a9bb5f71..0babd23573 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -410,6 +410,19 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) {
bgSurface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ // In case we pass the very big inset without any checking.
+ fgSurface->mInputInfo.surfaceInset = INT32_MAX;
+ fgSurface->showAt(100, 100);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // expect no crash for overflow, and inset size to be clamped to surface size
+ injectTap(202, 202);
+ fgSurface->expectTap(1, 1);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 940ff5afbc..e8154a6931 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -21,22 +21,7 @@ cc_library_shared {
"-Werror",
],
cppflags: [
- "-Weverything",
-
- // The static constructors and destructors in this library have not been noted to
- // introduce significant overheads
- "-Wno-exit-time-destructors",
- "-Wno-global-constructors",
-
- // We only care about compiling as C++14
- "-Wno-c++98-compat-pedantic",
-
- // android/sensors.h uses nested anonymous unions and anonymous structs
- "-Wno-nested-anon-types",
- "-Wno-gnu-anonymous-struct",
-
- // Don't warn about struct padding
- "-Wno-padded",
+ "-Wextra",
],
srcs: [
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 139987e6a9..abc910302c 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -577,7 +577,8 @@ void Sensor::flattenString8(void*& buffer, size_t& size,
uint32_t len = static_cast<uint32_t>(string8.length());
FlattenableUtils::write(buffer, size, len);
memcpy(static_cast<char*>(buffer), string8.string(), len);
- FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+ FlattenableUtils::advance(buffer, size, len);
+ size -= FlattenableUtils::align<4>(buffer);
}
bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2518e9374d..db15e17524 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -26,28 +26,7 @@ cc_library_shared {
"-Werror",
],
cppflags: [
- "-Weverything",
-
- // The static constructors and destructors in this library have not been noted to
- // introduce significant overheads
- "-Wno-exit-time-destructors",
- "-Wno-global-constructors",
-
- // We only care about compiling as C++14
- "-Wno-c++98-compat-pedantic",
-
- // We are aware of the risks inherent in comparing floats for equality
- "-Wno-float-equal",
-
- // We use four-character constants for the GraphicBuffer header, and don't care
- // that they're non-portable as long as they're consistent within one execution
- "-Wno-four-char-constants",
-
- // Don't warn about struct padding
- "-Wno-padded",
-
- "-Wno-switch-enum",
- "-Wno-format-pedantic",
+ "-Wextra",
],
sanitize: {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index e996be6853..a3bb6debe9 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -61,7 +61,7 @@ namespace android {
using nsecs_t = int64_t;
-struct extention_map_t {
+struct extension_map_t {
const char* name;
__eglMustCastToProperFunctionPointerType address;
};
@@ -154,7 +154,7 @@ char const * const gClientExtensionString =
* (keep in sync with gExtensionString above)
*
*/
-static const extention_map_t sExtensionMap[] = {
+static const extension_map_t sExtensionMap[] = {
// EGL_KHR_lock_surface
{ "eglLockSurfaceKHR",
(__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
@@ -257,13 +257,14 @@ static const extention_map_t sExtensionMap[] = {
!strcmp((procname), "eglAwakenProcessIMG"))
// accesses protected by sExtensionMapMutex
-static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtensionMap;
+static std::unordered_map<std::string, int> sGLExtensionSlotMap;
-static int sGLExtentionSlot = 0;
+static int sGLExtensionSlot = 0;
static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
static void(*findProcAddress(const char* name,
- const extention_map_t* map, size_t n))() {
+ const extension_map_t* map, size_t n))() {
for (uint32_t i=0 ; i<n ; i++) {
if (!strcmp(name, map[i].name)) {
return map[i].address;
@@ -1223,7 +1224,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn
addr = findBuiltinWrapper(procname);
if (addr) return addr;
- // this protects accesses to sGLExtentionMap and sGLExtentionSlot
+ // this protects accesses to sGLExtensionMap, sGLExtensionSlot, and sGLExtensionSlotMap
pthread_mutex_lock(&sExtensionMapMutex);
/*
@@ -1244,51 +1245,69 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn
*/
const std::string name(procname);
+ auto& extensionMap = sGLExtensionMap;
+ auto& extensionSlotMap = sGLExtensionSlotMap;
+ egl_connection_t* const cnx = &gEGLImpl;
+ LayerLoader& layer_loader(LayerLoader::getInstance());
- auto& extentionMap = sGLExtentionMap;
- auto pos = extentionMap.find(name);
- addr = (pos != extentionMap.end()) ? pos->second : nullptr;
- const int slot = sGLExtentionSlot;
+ // See if we've already looked up this extension
+ auto pos = extensionMap.find(name);
+ addr = (pos != extensionMap.end()) ? pos->second : nullptr;
- ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
- "no more slots for eglGetProcAddress(\"%s\")",
- procname);
+ if (!addr) {
+ // This is the first time we've looked this function up
+ // Ensure we have room to track it
+ const int slot = sGLExtensionSlot;
+ if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) {
- egl_connection_t* const cnx = &gEGLImpl;
- LayerLoader& layer_loader(LayerLoader::getInstance());
+ if (cnx->dso && cnx->egl.eglGetProcAddress) {
- if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
+ // Extensions are independent of the bound context
+ addr = cnx->egl.eglGetProcAddress(procname);
+ if (addr) {
- if (cnx->dso && cnx->egl.eglGetProcAddress) {
+ // purposefully track the bottom of the stack in extensionMap
+ extensionMap[name] = addr;
- // Extensions are independent of the bound context
- addr = cnx->egl.eglGetProcAddress(procname);
- if (addr) {
+ // Apply layers
+ addr = layer_loader.ApplyLayers(procname, addr);
- // purposefully track the bottom of the stack in extensionMap
- extentionMap[name] = addr;
+ // Track the top most entry point return the extension forwarder
+ cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
+ cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr;
+ addr = gExtensionForwarders[slot];
- // Apply layers
- addr = layer_loader.ApplyLayers(procname, addr);
+ // Remember the slot for this extension
+ extensionSlotMap[name] = slot;
- // Track the top most entry point
- cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr;
- addr = gExtensionForwarders[slot];
- sGLExtentionSlot++;
+ // Increment the global extension index
+ sGLExtensionSlot++;
+ }
}
+ } else {
+ // The extension forwarder has a fixed number of slots
+ ALOGE("no more slots for eglGetProcAddress(\"%s\")", procname);
}
- } else if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) {
+ } else {
+ // We tracked an address, so we've seen this func before
+ // Look up the slot for this extension
+ auto slot_pos = extensionSlotMap.find(name);
+ int ext_slot = (slot_pos != extensionSlotMap.end()) ? slot_pos->second : -1;
+ if (ext_slot < 0) {
+ // Something has gone wrong, this should not happen
+ ALOGE("No extension slot found for %s", procname);
+ return nullptr;
+ }
- // We've seen this func before, but we tracked the bottom, so re-apply layers
- // More layers might have been enabled
+ // We tracked the bottom of the stack, so re-apply layers since
+ // more layers might have been enabled
addr = layer_loader.ApplyLayers(procname, addr);
- // Track the top most entry point
- cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr;
- addr = gExtensionForwarders[slot];
+ // Track the top most entry point and return the extension forwarder
+ cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[ext_slot] =
+ cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[ext_slot] = addr;
+ addr = gExtensionForwarders[ext_slot];
}
pthread_mutex_unlock(&sExtensionMapMutex);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6c1a8aa7a6..3e6ddedf48 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2036,13 +2036,6 @@ bool Layer::isRemovedFromCurrentState() const {
return mRemovedFromCurrentState;
}
-// Debug helper for b/137560795
-#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
-
-#define RECT_BOUNDS_INVALID(rect) \
- (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
- INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
-
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
@@ -2053,14 +2046,14 @@ InputWindowInfo Layer::fillInputInfo() {
ui::Transform t = getTransform();
const float xScale = t.sx();
const float yScale = t.sy();
- float xSurfaceInset = info.surfaceInset;
- float ySurfaceInset = info.surfaceInset;
+ int32_t xSurfaceInset = info.surfaceInset;
+ int32_t ySurfaceInset = info.surfaceInset;
if (xScale != 1.0f || yScale != 1.0f) {
- info.windowXScale *= 1.0f / xScale;
- info.windowYScale *= 1.0f / yScale;
+ info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f;
+ info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f;
info.touchableRegion.scaleSelf(xScale, yScale);
- xSurfaceInset *= xScale;
- ySurfaceInset *= yScale;
+ xSurfaceInset = std::round(xSurfaceInset * xScale);
+ ySurfaceInset = std::round(ySurfaceInset * yScale);
}
// Transform layer size to screen space and inset it by surface insets.
@@ -2073,25 +2066,10 @@ InputWindowInfo Layer::fillInputInfo() {
}
layerBounds = t.transform(layerBounds);
- // debug check for b/137560795
- {
- if (RECT_BOUNDS_INVALID(layerBounds)) {
- ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
- ")",
- mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
- layerBounds.bottom);
- std::string out;
- getTransform().dump(out, "Transform");
- ALOGE("%s", out.c_str());
- layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
- }
+ // clamp inset to layer bounds
+ xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
+ ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
- if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
- ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
- int32_t(xSurfaceInset), int32_t(ySurfaceInset));
- xSurfaceInset = ySurfaceInset = 0;
- }
- }
layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
// Input coordinate should match the layer bounds.
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index b0c4f3f95a..4d6b2be301 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -41,12 +41,13 @@ cc_library_shared {
"-DVK_NO_PROTOTYPES",
"-fvisibility=hidden",
"-fstrict-aliasing",
- "-Weverything",
+ "-Wextra",
"-Werror",
"-Wno-padded",
+ "-Wno-sign-compare",
"-Wno-switch-enum",
- "-Wno-undef",
- "-Wno-format-pedantic",
+ "-Wno-unused-variable",
+ "-Wno-unused-function",
// Have clang emit complete debug_info.
"-fstandalone-debug",
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
index dedf419dc3..ba025046fa 100644
--- a/vulkan/nulldrv/Android.bp
+++ b/vulkan/nulldrv/Android.bp
@@ -23,18 +23,11 @@ cc_library_shared {
"-fvisibility=hidden",
"-fstrict-aliasing",
"-DLOG_TAG=\"vknulldrv\"",
- "-Weverything",
+ "-Wextra",
"-Werror",
- "-Wno-padded",
- "-Wno-undef",
- "-Wno-zero-length-array",
"-DLOG_NDEBUG=0",
],
- cppflags: [
- "-Wno-c++98-compat-pedantic",
- "-Wno-c99-extensions",
- ],
srcs: [
"null_driver.cpp",
diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp
index 2514094a15..91d64fe1c9 100644
--- a/vulkan/tools/Android.bp
+++ b/vulkan/tools/Android.bp
@@ -22,16 +22,8 @@ cc_binary {
"-DLOG_TAG=\"vkinfo\"",
- "-Weverything",
+ "-Wextra",
"-Werror",
- "-Wno-padded",
- "-Wno-undef",
- "-Wno-switch-enum",
- ],
- cppflags: [
- "-Wno-c++98-compat-pedantic",
- "-Wno-c99-extensions",
- "-Wno-old-style-cast",
],
srcs: ["vkinfo.cpp"],