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