1 /*
2  * Copyright 2019 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 
17 #include "annotation_util.h"
18 
19 #include <cstdlib>
20 
21 #define LOG_TAG "TuningFork"
22 #include "Log.h"
23 
24 namespace annotation_util {
25 
26 typedef uint64_t AnnotationId;
27 
28 // This is a protobuf 1-based index
GetKeyIndex(uint8_t b)29 int GetKeyIndex(uint8_t b) {
30     int type = b & 0x7;
31     if (type != 0) return kKeyError;
32     return b >> 3;
33 }
34 
GetBase128IntegerFromByteStream(const std::vector<uint8_t> & bytes,int & index)35 uint64_t GetBase128IntegerFromByteStream(const std::vector<uint8_t> &bytes, int &index) {
36     uint64_t m = 0;
37     uint64_t r = 0;
38     while (index < bytes.size() && m <= (64 - 7)) {
39         auto b = bytes[index];
40         r |= (((uint64_t) b) & 0x7f) << m;
41         if ((b & 0x80) != 0) m += 7;
42         else return r;
43         ++index;
44     }
45     return kStreamError;
46 }
47 
WriteBase128IntToStream(uint64_t x,std::vector<uint8_t> & bytes)48 void WriteBase128IntToStream(uint64_t x, std::vector<uint8_t> &bytes) {
49     do {
50         uint8_t a = x & 0x7f;
51         int b = x & 0xffffffffffffff80;
52         if (b) {
53             bytes.push_back(a | 0x80);
54             x >>= 7;
55         } else {
56             bytes.push_back(a);
57             return;
58         }
59     } while(x);
60 }
61 
DecodeAnnotationSerialization(const SerializedAnnotation & ser,const std::vector<int> & radix_mult)62 AnnotationId DecodeAnnotationSerialization(const SerializedAnnotation &ser,
63                                            const std::vector<int>& radix_mult) {
64     AnnotationId result = 0;
65     for (int i = 0; i < ser.size(); ++i) {
66         int key = GetKeyIndex(ser[i]);
67         if (key == kKeyError)
68             return kAnnotationError;
69         // Convert to 0-based index
70         --key;
71         if (key >= radix_mult.size())
72             return kAnnotationError;
73         ++i;
74         if (i >= ser.size())
75             return kAnnotationError;
76         uint64_t value = GetBase128IntegerFromByteStream(ser, i);
77         if (value == kStreamError)
78             return kAnnotationError;
79         // Check the range of the value
80         if (value == 0 || value >= radix_mult[key])
81             return kAnnotationError;
82         // We don't allow enums with more that 255 values
83         if (value > 0xff)
84             return kAnnotationError;
85         if (key > 0)
86             result += radix_mult[key - 1] * value;
87         else
88             result += value;
89     }
90     return result;
91 }
92 
SerializeAnnotationId(uint64_t id,SerializedAnnotation & ser,const std::vector<int> & radix_mult)93 int SerializeAnnotationId(uint64_t id, SerializedAnnotation& ser,
94                           const std::vector<int>& radix_mult) {
95   int err = 0;
96   uint64_t x = id;
97   for (int i = 0; i < radix_mult.size(); ++i) {
98     auto r = ::div(x, radix_mult[i]);
99     int value = r.rem;
100     if (value > 0) {
101       int key = (i + 1) << 3;
102       ser.push_back(key);
103       WriteBase128IntToStream(value, ser);
104     }
105     x = r.quot;
106   }
107   return err;
108 }
109 
SetUpAnnotationRadixes(std::vector<int> & radix_mult,const std::vector<int> & enum_sizes)110 void SetUpAnnotationRadixes( std::vector<int>& radix_mult,
111                              const std::vector<int>& enum_sizes) {
112     ALOGV("Settings::annotation_enum_size");
113     for(int i=0; i< enum_sizes.size();++i) {
114       ALOGV("%d", enum_sizes[i]);
115     }
116     int n = enum_sizes.size();
117     if (n == 0) {
118         // With no annotations, we just have 1 possible prong per key
119         radix_mult.resize(1);
120         radix_mult[0] = 1;
121     } else {
122         radix_mult.resize(n);
123         int r = 1;
124         for (int i = 0; i < n; ++i) {
125             r *= enum_sizes[i] + 1;
126             radix_mult[i] = r;
127         }
128     }
129 }
130 
131 } // namespace annotation_util
132