• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #pragma once
18 
19 #include <android-base/logging.h>
20 
21 #include <chrono>
22 #include <regex>
23 #include <thread>
24 #include <vector>
25 
26 #include <android-base/parseint.h>
27 using ::android::base::ParseInt;
28 
29 namespace aidl::android::hardware::biometrics {
30 
31 #define SLEEP_MS(x) \
32     if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
33 #define BEGIN_OP(x)            \
34     do {                       \
35         LOG(INFO) << __func__; \
36         SLEEP_MS(x);           \
37     } while (0)
38 #define IS_TRUE(x) ((x == "1") || (x == "true"))
39 
40 // This is for non-test situations, such as casual cuttlefish users, that don't
41 // set an explicit value.
42 // Some operations (i.e. enroll, authenticate) will be executed in tight loops
43 // by parts of the UI or fail if there is no latency. For example, the
44 // Face settings page constantly runs auth and the enrollment UI uses a
45 // cancel/restart cycle that requires some latency while the activities change.
46 #define DEFAULT_LATENCY 400
47 
48 class Util {
49   public:
getSystemNanoTime()50     static int64_t getSystemNanoTime() {
51         timespec now;
52         clock_gettime(CLOCK_MONOTONIC, &now);
53         return now.tv_sec * 1000000000LL + now.tv_nsec;
54     }
55 
hasElapsed(int64_t start,int64_t durationMillis)56     static bool hasElapsed(int64_t start, int64_t durationMillis) {
57         auto now = getSystemNanoTime();
58         if (now < start) return true;
59         if (durationMillis <= 0) return true;
60         return ((now - start) / 1000000LL) > durationMillis;
61     }
62 
split(const std::string & str,const std::string & sep)63     static std::vector<std::string> split(const std::string& str, const std::string& sep) {
64         std::regex regex(sep);
65         std::vector<std::string> parts(
66                 std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
67                 std::sregex_token_iterator());
68         return parts;
69     }
70 
71     // Returns a vector of integers for the string separated by comma,
72     // Empty vector is returned if there is any parsing error
73     static std::vector<int32_t> parseIntSequence(const std::string& str,
74                                                  const std::string& sep = ",") {
75         std::vector<std::string> seqs = Util::split(str, sep);
76         std::vector<int32_t> res;
77 
78         for (const auto& seq : seqs) {
79             int32_t val;
80             if (ParseInt(seq, &val)) {
81                 res.push_back(val);
82             } else {
83                 if (!str.empty()) {
84                     LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
85                 }
86                 res.clear();
87                 break;
88             }
89         }
90 
91         return res;
92     }
93 
94     // Parses a single enrollment stage string in the format of
95     //     enroll_stage_spec: <duration>[-acquiredInfos]
96     //                                      duration: integerInMs
97     //                                      acquiredInfos: [info1,info2,...]
98     //
99     // Returns false if there is parsing error
100     //
parseEnrollmentCaptureSingle(const std::string & str,std::vector<std::vector<int32_t>> & res)101     static bool parseEnrollmentCaptureSingle(const std::string& str,
102                                              std::vector<std::vector<int32_t>>& res) {
103         std::vector<int32_t> defaultAcquiredInfo = {1};
104         bool aborted = true;
105 
106         do {
107             std::smatch sms;
108             // Parses strings like "1000-[5,1]" or "500"
109             std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
110             if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
111             int32_t duration;
112             if (!ParseInt(sms.str(2), &duration)) break;
113             res.push_back({duration});
114             if (!sms.str(4).empty()) {
115                 auto acqv = parseIntSequence(sms.str(4));
116                 if (acqv.empty()) break;
117                 res.push_back(acqv);
118             } else
119                 res.push_back(defaultAcquiredInfo);
120             aborted = false;
121         } while (0);
122 
123         return !aborted;
124     }
125 
126     // Parses enrollment string consisting of one or more stages in the formst of
127     //  <enroll_stage_spec>[,enroll_stage_spec,...]
128     // Empty vector is returned in case of parsing error
parseEnrollmentCapture(const std::string & str)129     static std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str) {
130         std::vector<std::vector<int32_t>> res;
131 
132         std::string s(str);
133         s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
134         bool aborted = false;
135         std::smatch sms;
136         // Parses strings like "1000-[5,1],500,800-[6,5,1]"
137         //                               -------------- ----- ---------------
138         //  into parts:                       A       B       C
139         while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
140             if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
141                 aborted = true;
142                 break;
143             }
144             s = sms.suffix();
145         }
146         if (aborted || s.length() != 0) {
147             res.clear();
148             LOG(ERROR) << "Failed to parse enrollment captures:" + str;
149         }
150 
151         return res;
152     }
153 };
154 
155 }  // namespace aidl::android::hardware::biometrics
156