/* * 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 "include/StatsEventCompat.h" #include #include #include #include #include #include using android::base::boot_clock; using android::base::GetProperty; const static int kStatsEventTag = 1937006964; const bool StatsEventCompat::mPlatformAtLeastR = android_get_device_api_level() >= __ANDROID_API_R__; // initializations of static class variables bool StatsEventCompat::mAttemptedLoad = false; std::mutex StatsEventCompat::mLoadLock; AStatsEventApi StatsEventCompat::mAStatsEventApi; static int64_t elapsedRealtimeNano() { return std::chrono::time_point_cast(boot_clock::now()) .time_since_epoch() .count(); } StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) { // guard loading because StatsEventCompat might be called from multithreaded // environment { std::lock_guard lg(mLoadLock); if (!mAttemptedLoad && mPlatformAtLeastR) { void* handle = dlopen("libstatssocket.so", RTLD_NOW); if (handle) { initializeApiTableLocked(handle); } else { ALOGE("dlopen failed: %s\n", dlerror()); } } mAttemptedLoad = true; } if (useRSchema()) { mEventR = mAStatsEventApi.obtain(); } else if (useQSchema()) { mEventQ << elapsedRealtimeNano(); } } StatsEventCompat::~StatsEventCompat() { if (useRSchema()) mAStatsEventApi.release(mEventR); } // Populates the AStatsEventApi struct by calling dlsym to find the address of // each API function. void StatsEventCompat::initializeApiTableLocked(void* handle) { mAStatsEventApi.obtain = (AStatsEvent* (*)())dlsym(handle, "AStatsEvent_obtain"); mAStatsEventApi.build = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_build"); mAStatsEventApi.write = (int (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_write"); mAStatsEventApi.release = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_release"); mAStatsEventApi.setAtomId = (void (*)(AStatsEvent*, uint32_t))dlsym(handle, "AStatsEvent_setAtomId"); mAStatsEventApi.writeInt32 = (void (*)(AStatsEvent*, int32_t))dlsym(handle, "AStatsEvent_writeInt32"); mAStatsEventApi.writeInt64 = (void (*)(AStatsEvent*, int64_t))dlsym(handle, "AStatsEvent_writeInt64"); mAStatsEventApi.writeFloat = (void (*)(AStatsEvent*, float))dlsym(handle, "AStatsEvent_writeFloat"); mAStatsEventApi.writeBool = (void (*)(AStatsEvent*, bool))dlsym(handle, "AStatsEvent_writeBool"); mAStatsEventApi.writeByteArray = (void (*)(AStatsEvent*, const uint8_t*, size_t))dlsym( handle, "AStatsEvent_writeByteArray"); mAStatsEventApi.writeString = (void (*)(AStatsEvent*, const char*))dlsym(handle, "AStatsEvent_writeString"); mAStatsEventApi.writeAttributionChain = (void (*)(AStatsEvent*, const uint32_t*, const char* const*, uint8_t))dlsym( handle, "AStatsEvent_writeAttributionChain"); mAStatsEventApi.addBoolAnnotation = (void (*)(AStatsEvent*, uint8_t, bool))dlsym(handle, "AStatsEvent_addBoolAnnotation"); mAStatsEventApi.addInt32Annotation = (void (*)(AStatsEvent*, uint8_t, int32_t))dlsym( handle, "AStatsEvent_addInt32Annotation"); mAStatsEventApi.initialized = true; } void StatsEventCompat::setAtomId(int32_t atomId) { if (useRSchema()) { mAStatsEventApi.setAtomId(mEventR, (uint32_t)atomId); } else if (useQSchema()) { mEventQ << atomId; } } void StatsEventCompat::writeInt32(int32_t value) { if (useRSchema()) { mAStatsEventApi.writeInt32(mEventR, value); } else if (useQSchema()) { mEventQ << value; } } void StatsEventCompat::writeInt64(int64_t value) { if (useRSchema()) { mAStatsEventApi.writeInt64(mEventR, value); } else if (useQSchema()) { mEventQ << value; } } void StatsEventCompat::writeFloat(float value) { if (useRSchema()) { mAStatsEventApi.writeFloat(mEventR, value); } else if (useQSchema()) { mEventQ << value; } } void StatsEventCompat::writeBool(bool value) { if (useRSchema()) { mAStatsEventApi.writeBool(mEventR, value); } else if (useQSchema()) { mEventQ << value; } } void StatsEventCompat::writeByteArray(const char* buffer, size_t length) { if (useRSchema()) { mAStatsEventApi.writeByteArray(mEventR, reinterpret_cast(buffer), length); } else if (useQSchema()) { mEventQ.AppendCharArray(buffer, length); } } void StatsEventCompat::writeString(const char* value) { if (value == nullptr) value = ""; if (useRSchema()) { mAStatsEventApi.writeString(mEventR, value); } else if (useQSchema()) { mEventQ << value; } } void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids, const vector& tags) { if (useRSchema()) { mAStatsEventApi.writeAttributionChain(mEventR, (const uint32_t*)uids, tags.data(), (uint8_t)numUids); } else if (useQSchema()) { mEventQ.begin(); for (size_t i = 0; i < numUids; i++) { mEventQ.begin(); mEventQ << uids[i]; const char* tag = tags[i] ? tags[i] : ""; mEventQ << tag; mEventQ.end(); } mEventQ.end(); } } void StatsEventCompat::writeKeyValuePairs(const map& int32Map, const map& int64Map, const map& stringMap, const map& floatMap) { // AStatsEvent does not support key value pairs. if (useQSchema()) { mEventQ.begin(); writeKeyValuePairMap(int32Map); writeKeyValuePairMap(int64Map); writeKeyValuePairMap(stringMap); writeKeyValuePairMap(floatMap); mEventQ.end(); } } template void StatsEventCompat::writeKeyValuePairMap(const map& keyValuePairMap) { for (const auto& it : keyValuePairMap) { mEventQ.begin(); mEventQ << it.first; mEventQ << it.second; mEventQ.end(); } } // explicitly specify which types we're going to use template void StatsEventCompat::writeKeyValuePairMap(const map&); template void StatsEventCompat::writeKeyValuePairMap(const map&); template void StatsEventCompat::writeKeyValuePairMap(const map&); template void StatsEventCompat::writeKeyValuePairMap(const map&); void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) { if (useRSchema()) { mAStatsEventApi.addBoolAnnotation(mEventR, annotationId, value); } // Don't do anything if on Q. } void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) { if (useRSchema()) { mAStatsEventApi.addInt32Annotation(mEventR, annotationId, value); } // Don't do anything if on Q. } int StatsEventCompat::writeToSocket() { if (useRSchema()) { return mAStatsEventApi.write(mEventR); } if (useQSchema()) return mEventQ.write(LOG_ID_STATS); // We reach here only if we're on R, but libstatssocket was unable to // be loaded using dlopen. return -ENOLINK; } bool StatsEventCompat::useRSchema() { return mPlatformAtLeastR && mAStatsEventApi.initialized; } bool StatsEventCompat::useQSchema() { return !mPlatformAtLeastR; }