blob: bff7c9b44386a4b1335edf2d18b63b67a4530ec3 [file] [log] [blame]
/*
* Copyright (C) 2016 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.
*/
#ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
#include "MediaMetrics.h"
#include <algorithm>
#include <string>
#include <sys/types.h>
#include <cutils/properties.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
namespace android {
class IMediaAnalyticsService;
class Parcel;
/*
* MediaMetrics Item
*
* Byte string format.
*
* For Java
* int64 corresponds to long
* int32, uint32 corresponds to int
* uint16 corresponds to char
* uint8, int8 corresponds to byte
*
* Hence uint8 and uint32 values are limited to INT8_MAX and INT32_MAX.
*
* Physical layout of integers and doubles within the MediaMetrics byte string
* is in Native / host order, which is nearly always little endian.
*
* -- begin of item
* -- begin of header
* (uint32) item size: including the item size field
* (uint32) header size, including the item size and header size fields.
* (uint16) version: exactly 0
* (uint16) key size, that is key strlen + 1 for zero termination.
* (int8)+ key string which is 0 terminated
* (int32) pid
* (int32) uid
* (int64) timestamp
* -- end of header
* -- begin body
* (uint32) number of properties
* -- repeat for number of properties
* (uint16) property size, including property size field itself
* (uint8) type of property
* (int8)+ key string, including 0 termination
* based on type of property (given above), one of:
* (int32)
* (int64)
* (double)
* (int8)+ for cstring, including 0 termination
* (int64, int64) for rate
* -- end body
* -- end of item
*/
namespace mediametrics {
// Type must match MediaMetrics.java
enum Type {
kTypeNone = 0,
kTypeInt32 = 1,
kTypeInt64 = 2,
kTypeDouble = 3,
kTypeCString = 4,
kTypeRate = 5,
};
template<size_t N>
static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
return !strncmp(s.c_str(), comp, N-1);
}
/**
* Media Metrics BaseItem
*
* A base class which contains utility static functions to write to a byte stream
* and access the Media Metrics service.
*/
class BaseItem {
friend class MediaMetricsDeathNotifier; // for dropInstance
// enabled 1, disabled 0
public:
// are we collecting analytics data
static bool isEnabled();
protected:
static constexpr const char * const EnabledProperty = "media.metrics.enabled";
static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
static const int EnabledProperty_default = 1;
// let's reuse a binder connection
static sp<IMediaAnalyticsService> sAnalyticsService;
static sp<IMediaAnalyticsService> getInstance();
static void dropInstance();
static bool submitBuffer(const char *buffer, size_t len);
static status_t writeToByteString(
const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
static status_t writeToByteString(
const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
static status_t writeToByteString(
const char *name, double value, char **bufferpptr, char *bufferptrmax);
static status_t writeToByteString(
const char *name, const std::pair<int64_t, int64_t> &value,
char **bufferpptr, char *bufferptrmax);
static status_t writeToByteString(
const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
static status_t writeToByteString(
const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax);
struct none_t {}; // for kTypeNone
static status_t writeToByteString(
const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
template<typename T>
static status_t sizeOfByteString(const char *name, const T& value) {
return 2 + 1 + strlen(name) + 1 + sizeof(value);
}
template<> // static
status_t sizeOfByteString(const char *name, char * const &value) {
return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
}
template<> // static
status_t sizeOfByteString(const char *name, const char * const &value) {
return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
}
template<> // static
status_t sizeOfByteString(const char *name, const none_t &) {
return 2 + 1 + strlen(name) + 1;
}
};
/**
* Media Metrics BufferedItem
*
* A base class which represents a put-only Media Metrics item, storing
* the Media Metrics data in a buffer with begin and end pointers.
*
* If a property key is entered twice, it will be stored in the buffer twice,
* and (implementation defined) the last value for that key will be used
* by the Media Metrics service.
*
* For realloc, a baseRealloc pointer must be passed in either explicitly
* or implicitly in the constructor. This will be updated with the value used on realloc.
*/
class BufferedItem : public BaseItem {
public:
static inline constexpr uint16_t kVersion = 0;
virtual ~BufferedItem() = default;
BufferedItem(const BufferedItem&) = delete;
BufferedItem& operator=(const BufferedItem&) = delete;
BufferedItem(const std::string key, char *begin, char *end)
: BufferedItem(key.c_str(), begin, end) { }
BufferedItem(const char *key, char *begin, char *end)
: BufferedItem(key, begin, end, nullptr) { }
BufferedItem(const char *key, char **begin, char *end)
: BufferedItem(key, *begin, end, begin) { }
BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
: mBegin(begin)
, mEnd(end)
, mBaseRealloc(baseRealloc)
{
init(key);
}
template<typename T>
BufferedItem &set(const char *key, const T& value) {
reallocFor(sizeOfByteString(key, value));
if (mStatus == NO_ERROR) {
mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
++mPropCount;
}
return *this;
}
template<typename T>
BufferedItem &set(const std::string& key, const T& value) {
return set(key.c_str(), value);
}
BufferedItem &setPid(pid_t pid) {
if (mStatus == NO_ERROR) {
copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
}
return *this;
}
BufferedItem &setUid(uid_t uid) {
if (mStatus == NO_ERROR) {
copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
}
return *this;
}
BufferedItem &setTimestamp(nsecs_t timestamp) {
if (mStatus == NO_ERROR) {
copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
}
return *this;
}
bool record() {
return updateHeader()
&& BaseItem::submitBuffer(getBuffer(), getLength());
}
bool isValid () const {
return mStatus == NO_ERROR;
}
char *getBuffer() const { return mBegin; }
size_t getLength() const { return mBptr - mBegin; }
size_t getRemaining() const { return mEnd - mBptr; }
size_t getCapacity() const { return mEnd - mBegin; }
bool updateHeader() {
if (mStatus != NO_ERROR) return false;
copyTo(mBegin + 0, (uint32_t)getLength());
copyTo(mBegin + 4, (uint32_t)mHeaderLen);
copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
return true;
}
protected:
BufferedItem() = default;
void reallocFor(size_t required) {
if (mStatus != NO_ERROR) return;
const size_t remaining = getRemaining();
if (required <= remaining) return;
if (mBaseRealloc == nullptr) {
mStatus = NO_MEMORY;
return;
}
const size_t current = getLength();
size_t minimum = current + required;
if (minimum > SSIZE_MAX >> 1) {
mStatus = NO_MEMORY;
return;
}
minimum <<= 1;
void *newptr = realloc(*mBaseRealloc, minimum);
if (newptr == nullptr) {
mStatus = NO_MEMORY;
return;
}
if (newptr != *mBaseRealloc) {
// ALOGD("base changed! current:%zu new size %zu", current, minimum);
if (*mBaseRealloc == nullptr) {
memcpy(newptr, mBegin, current);
}
mBegin = (char *)newptr;
*mBaseRealloc = mBegin;
mEnd = mBegin + minimum;
mBptr = mBegin + current;
} else {
// ALOGD("base kept! current:%zu new size %zu", current, minimum);
mEnd = mBegin + minimum;
}
}
template<typename T>
void copyTo(char *ptr, const T& value) {
memcpy(ptr, &value, sizeof(value));
}
void init(const char *key) {
mBptr = mBegin;
const size_t keylen = strlen(key) + 1;
mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
reallocFor(mHeaderLen);
if (mStatus != NO_ERROR) return;
mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
if (mEnd < mBptr || keylen > UINT16_MAX) {
mStatus = NO_MEMORY;
mBptr = mEnd;
return;
}
copyTo(mBegin + 8, kVersion);
copyTo(mBegin + 10, (uint16_t)keylen);
strcpy(mBegin + 12, key);
// initialize some parameters (that could be overridden)
setPid(-1);
setUid(-1);
setTimestamp(0);
}
char *mBegin = nullptr;
char *mEnd = nullptr;
char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
// upon return, that pointer is updated with
// whatever needs to be freed.
char *mBptr = nullptr;
status_t mStatus = NO_ERROR;
uint32_t mPropCount = 0;
uint32_t mHeaderLen = 0;
};
/**
* MediaMetrics Item is a stack allocated media analytics item used for
* fast logging. It falls over to a malloc if needed.
*
* This is templated with a buffer size to allocate on the stack.
*/
template <size_t N = 4096>
class Item : public BufferedItem {
public:
explicit Item(const std::string key) : Item(key.c_str()) { }
// Since this class will not be defined before the base class, we initialize variables
// in our own order.
explicit Item(const char *key) {
mBegin = mBuffer;
mEnd = mBuffer + N;
mBaseRealloc = &mReallocPtr;
init(key);
}
~Item() override {
if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
free(mReallocPtr);
}
}
private:
char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
char mBuffer[N];
};
} // mediametrics
/**
* Media Metrics MediaAnalyticsItem
*
* A mutable item representing an event or record that will be
* logged with the Media Metrics service. For client logging, one should
* use the mediametrics::Item.
*
* The MediaAnalyticsItem is designed for the service as it has getters.
*/
class MediaAnalyticsItem : public mediametrics::BaseItem {
friend class MediaMetricsJNI; // TODO: remove this access
public:
// TODO: remove this duplicate definition when frameworks base is updated.
enum Type {
kTypeNone = 0,
kTypeInt32 = 1,
kTypeInt64 = 2,
kTypeDouble = 3,
kTypeCString = 4,
kTypeRate = 5,
};
static constexpr const char * const kKeyNone = "none";
static constexpr const char * const kKeyAny = "any";
enum {
PROTO_V0 = 0,
PROTO_FIRST = PROTO_V0,
PROTO_V1 = 1,
PROTO_LAST = PROTO_V1,
};
// T must be convertible to mKey
template <typename T>
explicit MediaAnalyticsItem(T key)
: mKey(key) { }
MediaAnalyticsItem() = default;
MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
bool operator==(const MediaAnalyticsItem& other) const {
if (mPropCount != other.mPropCount
|| mPid != other.mPid
|| mUid != other.mUid
|| mPkgName != other.mPkgName
|| mPkgVersionCode != other.mPkgVersionCode
|| mKey != other.mKey
|| mTimestamp != other.mTimestamp) return false;
for (size_t i = 0; i < mPropCount; ++i) {
Prop *p = other.findProp(mProps[i].getName());
if (p == nullptr || mProps[i] != *p) return false;
}
return true;
}
bool operator!=(const MediaAnalyticsItem& other) const {
return !(*this == other);
}
template <typename T>
static MediaAnalyticsItem* create(T key) {
return new MediaAnalyticsItem(key);
}
static MediaAnalyticsItem* create() {
return new MediaAnalyticsItem();
}
static MediaAnalyticsItem* convert(mediametrics_handle_t);
static mediametrics_handle_t convert(MediaAnalyticsItem *);
// access functions for the class
~MediaAnalyticsItem();
// reset all contents, discarding any extra data
void clear();
MediaAnalyticsItem *dup();
MediaAnalyticsItem &setKey(const char *key) {
mKey = key;
return *this;
}
const std::string& getKey() const { return mKey; }
// # of properties in the record
size_t count() const { return mPropCount; }
template<typename S, typename T>
MediaAnalyticsItem &set(S key, T value) {
allocateProp(key)->set(value);
return *this;
}
// set values appropriately
MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
return set(key, value);
}
MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
return set(key, value);
}
MediaAnalyticsItem &setDouble(const char *key, double value) {
return set(key, value);
}
MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
return set(key, std::make_pair(count, duration));
}
MediaAnalyticsItem &setCString(const char *key, const char *value) {
return set(key, value);
}
// fused get/add/set; if attr wasn't there, it's a simple set.
// type-mismatch counts as "wasn't there".
template<typename S, typename T>
MediaAnalyticsItem &add(S key, T value) {
allocateProp(key)->add(value);
return *this;
}
MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
return add(key, value);
}
MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
return add(key, value);
}
MediaAnalyticsItem &addDouble(const char *key, double value) {
return add(key, value);
}
MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
return add(key, std::make_pair(count, duration));
}
// find & extract values
// return indicates whether attr exists (and thus value filled in)
// NULL parameter value suppresses storage of value.
template<typename S, typename T>
bool get(S key, T *value) const {
Prop *prop = findProp(key);
return prop != nullptr && prop->get(value);
}
bool getInt32(const char *key, int32_t *value) const {
return get(key, value);
}
bool getInt64(const char *key, int64_t *value) const {
return get(key, value);
}
bool getDouble(const char *key, double *value) const {
return get(key, value);
}
bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
std::pair<int64_t, int64_t> value;
if (!get(key, &value)) return false;
if (count != nullptr) *count = value.first;
if (duration != nullptr) *duration = value.second;
if (rate != nullptr) {
if (value.second != 0) {
*rate = (double)value.first / value.second; // TODO: isn't INF OK?
} else {
*rate = 0.;
}
}
return true;
}
// Caller owns the returned string
bool getCString(const char *key, char **value) const {
const char *cs;
if (get(key, &cs)) {
*value = cs != nullptr ? strdup(cs) : nullptr;
return true;
}
return false;
}
bool getString(const char *key, std::string *value) const {
return get(key, value);
}
// Deliver the item to MediaMetrics
bool selfrecord();
// remove indicated attributes and their values
// filterNot() could also be called keepOnly()
// return value is # attributes removed
// XXX: perhaps 'remove' instead of 'filter'
// XXX: filterNot would become 'keep'
size_t filter(size_t count, const char *attrs[]);
size_t filterNot(size_t count, const char *attrs[]);
size_t filter(const char *attr) { return filter(1, &attr); }
// below here are used on server side or to talk to server
// clients need not worry about these.
// timestamp, pid, and uid only used on server side
// timestamp is in 'nanoseconds, unix time'
MediaAnalyticsItem &setTimestamp(nsecs_t);
nsecs_t getTimestamp() const;
MediaAnalyticsItem &setPid(pid_t);
pid_t getPid() const;
MediaAnalyticsItem &setUid(uid_t);
uid_t getUid() const;
MediaAnalyticsItem &setPkgName(const std::string &pkgName);
std::string getPkgName() const { return mPkgName; }
MediaAnalyticsItem &setPkgVersionCode(int64_t);
int64_t getPkgVersionCode() const;
// our serialization code for binder calls
status_t writeToParcel(Parcel *) const;
status_t readFromParcel(const Parcel&);
status_t writeToByteString(char **bufferptr, size_t *length) const;
status_t readFromByteString(const char *bufferptr, size_t length);
std::string toString() const;
std::string toString(int version) const;
const char *toCString();
const char *toCString(int version);
protected:
// merge fields from arg into this
// with rules for first/last/add, etc
// XXX: document semantics and how they are indicated
// caller continues to own 'incoming'
bool merge(MediaAnalyticsItem *incoming);
private:
// handle Parcel version 0
int32_t writeToParcel0(Parcel *) const;
int32_t readFromParcel0(const Parcel&);
// checks equality even with nullptr.
static bool stringEquals(const char *a, const char *b) {
if (a == nullptr) {
return b == nullptr;
} else {
return b != nullptr && strcmp(a, b) == 0;
}
}
public:
class Prop {
friend class MediaMetricsJNI; // TODO: remove this access
public:
Prop() = default;
Prop(const Prop& other) {
*this = other;
}
Prop& operator=(const Prop& other) {
if (other.mName != nullptr) {
mName = strdup(other.mName);
} else {
mName = nullptr;
}
mType = other.mType;
switch (mType) {
case kTypeInt32:
u.int32Value = other.u.int32Value;
break;
case kTypeInt64:
u.int64Value = other.u.int64Value;
break;
case kTypeDouble:
u.doubleValue = other.u.doubleValue;
break;
case kTypeCString:
u.CStringValue = strdup(other.u.CStringValue);
break;
case kTypeRate:
u.rate = other.u.rate;
break;
case kTypeNone:
break;
default:
// abort?
break;
}
return *this;
}
bool operator==(const Prop& other) const {
if (!stringEquals(mName, other.mName)
|| mType != other.mType) return false;
switch (mType) {
case kTypeInt32:
return u.int32Value == other.u.int32Value;
case kTypeInt64:
return u.int64Value == other.u.int64Value;
case kTypeDouble:
return u.doubleValue == other.u.doubleValue;
case kTypeCString:
return stringEquals(u.CStringValue, other.u.CStringValue);
case kTypeRate:
return u.rate == other.u.rate;
case kTypeNone:
default:
return true;
}
}
bool operator!=(const Prop& other) const {
return !(*this == other);
}
void clear() {
free(mName);
mName = nullptr;
clearValue();
}
void clearValue() {
if (mType == kTypeCString) {
free(u.CStringValue);
u.CStringValue = nullptr;
}
mType = kTypeNone;
}
Type getType() const {
return mType;
}
const char *getName() const {
return mName;
}
void swap(Prop& other) {
std::swap(mName, other.mName);
std::swap(mType, other.mType);
std::swap(u, other.u);
}
void setName(const char *name) {
free(mName);
if (name != nullptr) {
mName = strdup(name);
} else {
mName = nullptr;
}
}
bool isNamed(const char *name) const {
return stringEquals(name, mName);
}
template <typename T> void visit(T f) const {
switch (mType) {
case MediaAnalyticsItem::kTypeInt32:
f(u.int32Value);
return;
case MediaAnalyticsItem::kTypeInt64:
f(u.int64Value);
return;
case MediaAnalyticsItem::kTypeDouble:
f(u.doubleValue);
return;
case MediaAnalyticsItem::kTypeRate:
f(u.rate);
return;
case MediaAnalyticsItem::kTypeCString:
f(u.CStringValue);
return;
default:
return;
}
}
template <typename T> bool get(T *value) const = delete;
template <>
bool get(int32_t *value) const {
if (mType != kTypeInt32) return false;
if (value != nullptr) *value = u.int32Value;
return true;
}
template <>
bool get(int64_t *value) const {
if (mType != kTypeInt64) return false;
if (value != nullptr) *value = u.int64Value;
return true;
}
template <>
bool get(double *value) const {
if (mType != kTypeDouble) return false;
if (value != nullptr) *value = u.doubleValue;
return true;
}
template <>
bool get(const char** value) const {
if (mType != kTypeCString) return false;
if (value != nullptr) *value = u.CStringValue;
return true;
}
template <>
bool get(std::string* value) const {
if (mType != kTypeCString) return false;
if (value != nullptr) *value = u.CStringValue;
return true;
}
template <>
bool get(std::pair<int64_t, int64_t> *value) const {
if (mType != kTypeRate) return false;
if (value != nullptr) {
*value = u.rate;
}
return true;
}
template <typename T> void set(const T& value) = delete;
template <>
void set(const int32_t& value) {
mType = kTypeInt32;
u.int32Value = value;
}
template <>
void set(const int64_t& value) {
mType = kTypeInt64;
u.int64Value = value;
}
template <>
void set(const double& value) {
mType = kTypeDouble;
u.doubleValue = value;
}
template <>
void set(const char* const& value) {
if (mType == kTypeCString) {
free(u.CStringValue);
} else {
mType = kTypeCString;
}
if (value == nullptr) {
u.CStringValue = nullptr;
} else {
size_t len = strlen(value);
if (len > UINT16_MAX - 1) {
len = UINT16_MAX - 1;
}
u.CStringValue = (char *)malloc(len + 1);
strncpy(u.CStringValue, value, len);
u.CStringValue[len] = 0;
}
}
template <>
void set(const std::pair<int64_t, int64_t> &value) {
mType = kTypeRate;
u.rate = {value.first, value.second};
}
template <typename T> void add(const T& value) = delete;
template <>
void add(const int32_t& value) {
if (mType == kTypeInt32) {
u.int32Value += value;
} else {
mType = kTypeInt32;
u.int32Value = value;
}
}
template <>
void add(const int64_t& value) {
if (mType == kTypeInt64) {
u.int64Value += value;
} else {
mType = kTypeInt64;
u.int64Value = value;
}
}
template <>
void add(const double& value) {
if (mType == kTypeDouble) {
u.doubleValue += value;
} else {
mType = kTypeDouble;
u.doubleValue = value;
}
}
template <>
void add(const std::pair<int64_t, int64_t>& value) {
if (mType == kTypeRate) {
u.rate.first += value.first;
u.rate.second += value.second;
} else {
mType = kTypeRate;
u.rate = value;
}
}
status_t writeToParcel(Parcel *data) const;
status_t readFromParcel(const Parcel& data);
void toString(char *buffer, size_t length) const;
size_t getByteStringSize() const;
status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
// TODO: make private (and consider converting to std::variant)
// private:
char *mName = nullptr;
Type mType = kTypeNone;
union u__ {
u__() { zero(); }
u__(u__ &&other) {
*this = std::move(other);
}
u__& operator=(u__ &&other) {
memcpy(this, &other, sizeof(*this));
other.zero();
return *this;
}
void zero() { memset(this, 0, sizeof(*this)); }
int32_t int32Value;
int64_t int64Value;
double doubleValue;
char *CStringValue;
std::pair<int64_t, int64_t> rate;
} u;
};
class iterator {
public:
iterator(size_t pos, const MediaAnalyticsItem &_item)
: i(std::min(pos, _item.count()))
, item(_item) { }
iterator &operator++() {
i = std::min(i + 1, item.count());
return *this;
}
bool operator!=(iterator &other) const {
return i != other.i;
}
Prop &operator*() const {
return item.mProps[i];
}
private:
size_t i;
const MediaAnalyticsItem &item;
};
iterator begin() const {
return iterator(0, *this);
}
iterator end() const {
return iterator(SIZE_MAX, *this);
}
private:
// TODO: make prop management class
size_t findPropIndex(const char *name) const;
Prop *findProp(const char *name) const;
Prop *allocateProp();
enum {
kGrowProps = 10
};
bool growProps(int increment = kGrowProps);
Prop *allocateProp(const char *name);
bool removeProp(const char *name);
Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
size_t mPropCount = 0;
size_t mPropSize = 0;
Prop *mProps = nullptr;
pid_t mPid = -1;
uid_t mUid = -1;
std::string mPkgName;
int64_t mPkgVersionCode = 0;
std::string mKey{kKeyNone};
nsecs_t mTimestamp = 0;
};
} // namespace android
#endif