1 /* 2 * Copyright (C) 2022 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 package com.android.testutils; 18 19 import static com.android.modules.utils.build.SdkLevel.isAtLeastS; 20 21 import android.os.Build; 22 import android.os.SystemProperties; 23 import android.os.VintfRuntimeInfo; 24 import android.text.TextUtils; 25 import android.util.Pair; 26 27 import java.util.Objects; 28 import java.util.regex.Matcher; 29 import java.util.regex.Pattern; 30 31 /** 32 * Utilities for device information. 33 */ 34 public class DeviceInfoUtils { 35 /** 36 * Class for a three-part kernel version number. 37 */ 38 public static class KVersion { 39 public final int major; 40 public final int minor; 41 public final int sub; 42 KVersion(int major, int minor, int sub)43 public KVersion(int major, int minor, int sub) { 44 this.major = major; 45 this.minor = minor; 46 this.sub = sub; 47 } 48 49 /** 50 * Compares with other version numerically. 51 * 52 * @param other the other version to compare 53 * @return the value 0 if this == other; 54 * a value less than 0 if this < other and 55 * a value greater than 0 if this > other. 56 */ compareTo(final KVersion other)57 public int compareTo(final KVersion other) { 58 int res = Integer.compare(this.major, other.major); 59 if (res == 0) { 60 res = Integer.compare(this.minor, other.minor); 61 } 62 if (res == 0) { 63 res = Integer.compare(this.sub, other.sub); 64 } 65 return res; 66 } 67 68 /** 69 * At least satisfied with the given version. 70 * 71 * @param from the start version to compare 72 * @return return true if this version is at least satisfied with the given version. 73 * otherwise, return false. 74 */ isAtLeast(final KVersion from)75 public boolean isAtLeast(final KVersion from) { 76 return compareTo(from) >= 0; 77 } 78 79 /** 80 * Falls within the given range [from, to). 81 * 82 * @param from the start version to compare 83 * @param to the end version to compare 84 * @return return true if this version falls within the given range. 85 * otherwise, return false. 86 */ isInRange(final KVersion from, final KVersion to)87 public boolean isInRange(final KVersion from, final KVersion to) { 88 return isAtLeast(from) && !isAtLeast(to); 89 } 90 91 @Override equals(Object o)92 public boolean equals(Object o) { 93 if (!(o instanceof KVersion)) return false; 94 KVersion that = (KVersion) o; 95 return this.major == that.major 96 && this.minor == that.minor 97 && this.sub == that.sub; 98 } 99 }; 100 101 /** 102 * Get a two-part kernel version number (major and minor) from a given string. 103 * 104 * TODO: use class KVersion. 105 */ getMajorMinorVersion(String version)106 private static Pair<Integer, Integer> getMajorMinorVersion(String version) { 107 // Only gets major and minor number of the version string. 108 final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*"); 109 final Matcher m = versionPattern.matcher(version); 110 if (m.matches()) { 111 final int major = Integer.parseInt(m.group(1)); 112 final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3)); 113 return new Pair<>(major, minor); 114 } else { 115 return new Pair<>(0, 0); 116 } 117 } 118 119 /** 120 * Compares two version strings numerically. Compare only major and minor number of the 121 * version string. The version comparison uses #Integer.compare. Possible version 122 * 5, 5.10, 5-beta1, 4.8-RC1, 4.7.10.10 and so on. 123 * 124 * @param s1 the first version string to compare 125 * @param s2 the second version string to compare 126 * @return the value 0 if s1 == s2; 127 * a value less than 0 if s1 < s2 and 128 * a value greater than 0 if s1 > s2. 129 * 130 * TODO: use class KVersion. 131 */ compareMajorMinorVersion(final String s1, final String s2)132 public static int compareMajorMinorVersion(final String s1, final String s2) { 133 final Pair<Integer, Integer> v1 = getMajorMinorVersion(s1); 134 final Pair<Integer, Integer> v2 = getMajorMinorVersion(s2); 135 136 if (Objects.equals(v1.first, v2.first)) { 137 return Integer.compare(v1.second, v2.second); 138 } else { 139 return Integer.compare(v1.first, v2.first); 140 } 141 } 142 143 /** 144 * Get a three-part kernel version number (major, minor and subminor) from a given string. 145 * Any version string must at least have major and minor number. If the subminor number can't 146 * be parsed from string. Assign zero as subminor number. Invalid version is treated as 147 * version 0.0.0. 148 */ getMajorMinorSubminorVersion(final String version)149 public static KVersion getMajorMinorSubminorVersion(final String version) { 150 // The kernel version is a three-part version number (major, minor and subminor). Get 151 // the three-part version numbers and discard the remaining stuff if any. 152 // For example: 153 // 4.19.220-g500ede0aed22-ab8272303 --> 4.19.220 154 // 5.17-rc6-g52099515ca00-ab8032400 --> 5.17.0 155 final Pattern versionPattern = Pattern.compile("^(\\d+)\\.(\\d+)(\\.(\\d+))?.*"); 156 final Matcher m = versionPattern.matcher(version); 157 if (m.matches()) { 158 final int major = Integer.parseInt(m.group(1)); 159 final int minor = Integer.parseInt(m.group(2)); 160 final int sub = TextUtils.isEmpty(m.group(4)) ? 0 : Integer.parseInt(m.group(4)); 161 return new KVersion(major, minor, sub); 162 } else { 163 return new KVersion(0, 0, 0); 164 } 165 } 166 167 /** 168 * Check if the current kernel version is at least satisfied with the given version. 169 * 170 * @param version the start version to compare 171 * @return return true if the current version is at least satisfied with the given version. 172 * otherwise, return false. 173 */ isKernelVersionAtLeast(final String version)174 public static boolean isKernelVersionAtLeast(final String version) { 175 final String kernelVersion = VintfRuntimeInfo.getKernelVersion(); 176 final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion); 177 final KVersion from = DeviceInfoUtils.getMajorMinorSubminorVersion(version); 178 return current.isAtLeast(from); 179 } 180 181 /** 182 * Check if the current build is a debuggable build. 183 */ isDebuggable()184 public static boolean isDebuggable() { 185 if (isAtLeastS()) { 186 return Build.isDebuggable(); 187 } 188 return SystemProperties.getInt("ro.debuggable", 0) == 1; 189 } 190 } 191