Merge "Native puller API: libstatspulled"
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
new file mode 100644
index 0000000..9772da1
--- /dev/null
+++ b/libstats/pull/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+
+// ==========================================================
+// Native library to register a pull atom callback with statsd
+// ==========================================================
+cc_library_shared {
+ name: "libstatspull",
+ srcs: [
+ ":statsd_aidl",
+ "stats_pull_atom_callback.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ //TODO: use libbinder_ndk.
+ "libbinder",
+ "libstatssocket",
+ "libservices",
+ ],
+ static_libs: [
+ "liblog",
+ "libutils",
+ ]
+}
diff --git a/libstats/pull/OWNERS b/libstats/pull/OWNERS
new file mode 100644
index 0000000..7855774
--- /dev/null
+++ b/libstats/pull/OWNERS
@@ -0,0 +1,7 @@
+joeo@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
new file mode 100644
index 0000000..ee69ea7
--- /dev/null
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Metadata for registering a stats_pull_atom_callback.
+ * All fields are optional, and defaults will be used for unspecified fields.
+ */
+typedef struct pull_atom_metadata {
+ int64_t cool_down_ns;
+ int64_t timeout_ns;
+ int32_t* additive_fields;
+ int32_t additive_fields_size;
+} pull_atom_metadata;
+
+typedef struct pulled_stats_event_list pulled_stats_event_list;
+
+typedef bool (*stats_pull_atom_callback_t)(int32_t atom_tag, pulled_stats_event_list* data,
+ const void* cookie);
+
+struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data);
+void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t* callback,
+ pull_atom_metadata* metadata, const void* cookie);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
new file mode 100644
index 0000000..f61d646
--- /dev/null
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 <map>
+#include <vector>
+
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+
+#include <android/os/BnPullAtomCallback.h>
+#include <android/os/IPullAtomResultReceiver.h>
+#include <android/os/IStatsManager.h>
+#include <android/util/StatsEvent.h>
+#include <binder/IServiceManager.h>
+#include "include/stats_pull_atom_callback.h"
+
+struct pulled_stats_event_list {
+ std::vector<stats_event*> data;
+};
+
+struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data) {
+ struct stats_event* event = stats_event_obtain();
+ pull_data->data.push_back(event);
+ return event;
+}
+
+static const int64_t DEFAULT_COOL_DOWN_NS = 1000000000LL; // 1 second.
+static const int64_t DEFAULT_TIMEOUT_NS = 10000000000LL; // 10 seconds.
+
+class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
+ public:
+ StatsPullAtomCallbackInternal(const stats_pull_atom_callback_t* callback, const void* cookie,
+ const int64_t coolDownNs, const int64_t timeoutNs,
+ const std::vector<int32_t> additiveFields)
+ : mCallback(callback),
+ mCookie(cookie),
+ mCoolDownNs(coolDownNs),
+ mTimeoutNs(timeoutNs),
+ mAdditiveFields(additiveFields) {}
+
+ ::android::binder::Status onPullAtom(
+ int32_t atomTag,
+ const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
+ pulled_stats_event_list statsEventList;
+ bool success = (*mCallback)(atomTag, &statsEventList, mCookie);
+ std::vector<android::util::StatsEvent> output;
+ // TODO convert stats_event into parcelable stats_event.
+ resultReceiver->pullFinished(atomTag, success, output);
+ for (int i = 0; i < statsEventList.data.size(); i++) {
+ stats_event_release(statsEventList.data[i]);
+ }
+ return android::binder::Status::ok();
+ }
+
+ const int64_t& getCoolDownNs() const { return mCoolDownNs; }
+ const int64_t& getTimeoutNs() const { return mTimeoutNs; }
+ const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
+
+ private:
+ const stats_pull_atom_callback_t* mCallback;
+ const void* mCookie;
+ const int64_t mCoolDownNs;
+ const int64_t mTimeoutNs;
+ const std::vector<int32_t> mAdditiveFields;
+};
+
+static std::mutex pullAtomMutex;
+static android::sp<android::os::IStatsManager> sStatsd = nullptr;
+
+static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
+static android::sp<android::os::IStatsManager> getStatsServiceLocked();
+
+class StatsDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ StatsDeathRecipient() = default;
+ ~StatsDeathRecipient() override = default;
+
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& /* who */) override {
+ std::lock_guard<std::mutex> lock(pullAtomMutex);
+ if (sStatsd) {
+ sStatsd = nullptr;
+ }
+ android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+ if (statsService == nullptr) {
+ return;
+ }
+ for (auto it : mPullers) {
+ statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownNs(),
+ it.second->getTimeoutNs(),
+ it.second->getAdditiveFields(), it.second);
+ }
+ }
+};
+
+static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
+
+static android::sp<android::os::IStatsManager> getStatsServiceLocked() {
+ if (!sStatsd) {
+ // Fetch statsd.
+ const android::sp<android::IBinder> binder =
+ android::defaultServiceManager()->checkService(android::String16("stats"));
+ if (!binder) {
+ return nullptr;
+ }
+ binder->linkToDeath(statsDeathRecipient);
+ sStatsd = android::interface_cast<android::os::IStatsManager>(binder);
+ }
+ return sStatsd;
+}
+
+void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t* callback,
+ pull_atom_metadata* metadata, void* cookie) {
+ int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
+ int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
+
+ std::vector<int32_t> additiveFields;
+ if (metadata != nullptr && metadata->additive_fields != nullptr) {
+ additiveFields.assign(metadata->additive_fields,
+ metadata->additive_fields + metadata->additive_fields_size);
+ }
+
+ std::lock_guard<std::mutex> lg(pullAtomMutex);
+ const android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+ if (statsService == nullptr) {
+ // Error - statsd not available
+ return;
+ }
+
+ android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
+ callback, cookie, coolDownNs, timeoutNs, additiveFields);
+ mPullers[atom_tag] = callbackBinder;
+ statsService->registerNativePullAtomCallback(atom_tag, coolDownNs, timeoutNs, additiveFields,
+ callbackBinder);
+}