1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
19
20namespace android {
21namespace os {
22namespace statsd {
23
24class HashableDimensionKey;
25struct Matcher;
26struct Field;
27struct FieldValue;
28
29const int32_t kAttributionField = 1;
30const int32_t kMaxLogDepth = 2;
31const int32_t kLastBitMask = 0x80;
32const int32_t kClearLastBitDeco = 0x7f;
33const int32_t kClearAllPositionMatcherMask = 0xffff00ff;
34
35enum Type { UNKNOWN, INT, LONG, FLOAT, STRING };
36
37int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
38
39int32_t encodeMatcherMask(int32_t mask[], int32_t depth);
40
41// Get the encoded field for a leaf with a [field] number at depth 0;
42inline int32_t getSimpleField(size_t field) {
43    return ((int32_t)field << 8 * 2);
44}
45
46/**
47 * Field is a wrapper class for 2 integers that represents the field of a log element in its Atom
48 * proto.
49 * [mTag]: the atom id.
50 * [mField]: encoded path from the root (atom) to leaf.
51 *
52 * For example:
53 * WakeLockStateChanged {
54 *    repeated AttributionNode = 1;
55 *    int state = 2;
56 *    string tag = 3;
57 * }
58 * Read from logd, the items are structured as below:
59 * [[[1000, "tag"], [2000, "tag2"],], 2,"hello"]
60 *
61 * When we read through the list, we will encode each field in a 32bit integer.
62 * 8bit segments   |--------|--------|--------|--------|
63 *                    Depth   field0 [L]field1 [L]field1
64 *
65 *  The first 8 bits are the depth of the field. for example, the uid 1000 has depth 2.
66 *  The following 3 8-bit are for the item's position at each level.
67 *  The first bit of each 8bits field is reserved to mark if the item is the last item at that level
68 *  this is to make matching easier later.
69 *
70 *  The above wakelock event is translated into FieldValue pairs.
71 *  0x02010101->1000
72 *  0x02010182->tag
73 *  0x02018201->2000
74 *  0x02018282->tag2
75 *  0x00020000->2
76 *  0x00030000->"hello"
77 *
78 *  This encoding is the building block for the later operations.
79 *  Please see the definition for Matcher below to see how the matching is done.
80 */
81struct Field {
82private:
83    int32_t mTag;
84    int32_t mField;
85
86public:
87    Field() {}
88
89    Field(int32_t tag, int32_t pos[], int32_t depth) : mTag(tag) {
90        mField = getEncodedField(pos, depth, true);
91    }
92
93    Field(const Field& from) : mTag(from.getTag()), mField(from.getField()) {
94    }
95
96    Field(int32_t tag, int32_t field) : mTag(tag), mField(field){};
97
98    inline void setField(int32_t field) {
99        mField = field;
100    }
101
102    inline void setTag(int32_t tag) {
103        mTag = tag;
104    }
105
106    inline void decorateLastPos(int32_t depth) {
107        int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
108        mField |= mask;
109    }
110
111    inline int32_t getTag() const {
112        return mTag;
113    }
114
115    inline int32_t getDepth() const {
116        return (mField >> 24);
117    }
118
119    inline int32_t getPath(int32_t depth) const {
120        if (depth > 2 || depth < 0) return 0;
121
122        int32_t field = (mField & 0x00ffffff);
123        int32_t mask = 0xffffffff;
124        return (field & (mask << 8 * (kMaxLogDepth - depth)));
125    }
126
127    inline int32_t getPrefix(int32_t depth) const {
128        if (depth == 0) return 0;
129        return getPath(depth - 1);
130    }
131
132    inline int32_t getField() const {
133        return mField;
134    }
135
136    inline int32_t getRawPosAtDepth(int32_t depth) const {
137        int32_t field = (mField & 0x00ffffff);
138        int32_t shift = 8 * (kMaxLogDepth - depth);
139        int32_t mask = 0xff << shift;
140
141        return (field & mask) >> shift;
142    }
143
144    inline int32_t getPosAtDepth(int32_t depth) const {
145        return getRawPosAtDepth(depth) & kClearLastBitDeco;
146    }
147
148    // Check if the first bit of the 8-bit segment for depth is 1
149    inline bool isLastPos(int32_t depth) const {
150        int32_t field = (mField & 0x00ffffff);
151        int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
152        return (field & mask) != 0;
153    }
154
155    // if the 8-bit segment is all 0's
156    inline bool isAnyPosMatcher(int32_t depth) const {
157        return getDepth() >= depth && getRawPosAtDepth(depth) == 0;
158    }
159    // if the 8bit is 0x80 (1000 0000)
160    inline bool isLastPosMatcher(int32_t depth) const {
161        return getDepth() >= depth && getRawPosAtDepth(depth) == kLastBitMask;
162    }
163
164    inline bool operator==(const Field& that) const {
165        return mTag == that.getTag() && mField == that.getField();
166    };
167
168    inline bool operator!=(const Field& that) const {
169        return mTag != that.getTag() || mField != that.getField();
170    };
171
172    bool operator<(const Field& that) const {
173        if (mTag != that.getTag()) {
174            return mTag < that.getTag();
175        }
176
177        if (mField != that.getField()) {
178            return mField < that.getField();
179        }
180
181        return false;
182    }
183    bool matches(const Matcher& that) const;
184};
185
186/**
187 * Matcher represents a leaf matcher in the FieldMatcher in statsd_config.
188 *
189 * It contains all information needed to match one or more leaf node.
190 * All information is encoded in a Field(2 ints) and a bit mask(1 int).
191 *
192 * For example, to match the first/any/last uid field in attribution chain in Atom 10,
193 * we have the following FieldMatcher in statsd_config
194 *    FieldMatcher {
195 *        field:10
196 *         FieldMatcher {
197 *              field:1
198 *              position: any/last/first
199 *              FieldMatcher {
200 *                  field:1
201 *              }
202 *          }
203 *     }
204 *
205 * We translate the FieldMatcher into a Field, and mask
206 * First: [Matcher Field] 0x02010101  [Mask]0xff7f7f7f
207 * Last:  [Matcher Field] 0x02018001  [Mask]0xff7f807f
208 * Any:   [Matcher Field] 0x02010001  [Mask]0xff7f007f
209 * All:   [Matcher Field] 0x02010001  [Mask]0xff7f7f7f
210 *
211 * [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if
212 * the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
213 * equal. Nothing can beat the performance of this matching algorithm.
214 *
215 * TODO: ADD EXAMPLE HERE.
216 */
217struct Matcher {
218    Matcher(const Field& matcher, int32_t mask) : mMatcher(matcher), mMask(mask){};
219
220    const Field mMatcher;
221    const int32_t mMask;
222
223    inline const Field& getMatcher() const {
224        return mMatcher;
225    }
226
227    inline int32_t getMask() const {
228        return mMask;
229    }
230
231    inline int32_t getRawMaskAtDepth(int32_t depth) const {
232        int32_t field = (mMask & 0x00ffffff);
233        int32_t shift = 8 * (kMaxLogDepth - depth);
234        int32_t mask = 0xff << shift;
235
236        return (field & mask) >> shift;
237    }
238
239    bool hasAllPositionMatcher() const {
240        return mMatcher.getDepth() == 2 && getRawMaskAtDepth(1) == 0x7f;
241    }
242
243    bool hasAnyPositionMatcher(int* prefix) const {
244        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(1) == 0) {
245            (*prefix) = mMatcher.getPrefix(1);
246            return true;
247        }
248        return false;
249    }
250
251    inline bool operator!=(const Matcher& that) const {
252        return mMatcher != that.getMatcher() || mMask != that.getMask();
253    }
254
255    inline bool operator==(const Matcher& that) const {
256        return mMatcher == that.mMatcher && mMask == that.mMask;
257    }
258};
259
260inline Matcher getSimpleMatcher(int32_t tag, size_t field) {
261    return Matcher(Field(tag, getSimpleField(field)), 0xff7f0000);
262}
263
264/**
265 * A wrapper for a union type to contain multiple types of values.
266 *
267 */
268struct Value {
269    Value() : type(UNKNOWN) {}
270
271    Value(int32_t v) {
272        int_value = v;
273        type = INT;
274    }
275
276    Value(int64_t v) {
277        long_value = v;
278        type = LONG;
279    }
280
281    Value(float v) {
282        float_value = v;
283        type = FLOAT;
284    }
285
286    Value(const std::string& v) {
287        str_value = v;
288        type = STRING;
289    }
290
291    void setInt(int32_t v) {
292        int_value = v;
293        type = INT;
294    }
295
296    void setLong(int64_t v) {
297        long_value = v;
298        type = LONG;
299    }
300
301    union {
302        int32_t int_value;
303        int64_t long_value;
304        float float_value;
305    };
306    std::string str_value;
307
308    Type type;
309
310    std::string toString() const;
311
312    Type getType() const {
313        return type;
314    }
315
316    Value(const Value& from);
317
318    bool operator==(const Value& that) const;
319    bool operator!=(const Value& that) const;
320
321    bool operator<(const Value& that) const;
322};
323
324/**
325 * Represents a log item, or a dimension item (They are essentially the same).
326 */
327struct FieldValue {
328    FieldValue() {}
329    FieldValue(const Field& field, const Value& value) : mField(field), mValue(value) {
330    }
331    bool operator==(const FieldValue& that) const {
332        return mField == that.mField && mValue == that.mValue;
333    }
334    bool operator!=(const FieldValue& that) const {
335        return mField != that.mField || mValue != that.mValue;
336    }
337    bool operator<(const FieldValue& that) const {
338        if (mField != that.mField) {
339            return mField < that.mField;
340        }
341
342        if (mValue != that.mValue) {
343            return mValue < that.mValue;
344        }
345
346        return false;
347    }
348
349    Field mField;
350    Value mValue;
351};
352
353bool HasPositionANY(const FieldMatcher& matcher);
354bool HasPositionALL(const FieldMatcher& matcher);
355
356bool isAttributionUidField(const FieldValue& value);
357
358void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
359
360bool isAttributionUidField(const Field& field, const Value& value);
361
362bool equalDimensions(const std::vector<Matcher>& dimension_a,
363                     const std::vector<Matcher>& dimension_b);
364}  // namespace statsd
365}  // namespace os
366}  // namespace android
367