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