summaryrefslogtreecommitdiff
path: root/common/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
blob: ce55fdc1d35a6bf53229ed054f7813e9987b1eda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.testutils;

import android.os.VintfRuntimeInfo;
import android.text.TextUtils;
import android.util.Pair;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Utilities for device information.
 */
public class DeviceInfoUtils {
    /**
     * Class for a three-part kernel version number.
     */
    public static class KVersion {
        public final int major;
        public final int minor;
        public final int sub;

        public KVersion(int major, int minor, int sub) {
            this.major = major;
            this.minor = minor;
            this.sub = sub;
        }

        /**
         * Compares with other version numerically.
         *
         * @param  other the other version to compare
         * @return the value 0 if this == other;
         *         a value less than 0 if this < other and
         *         a value greater than 0 if this > other.
         */
        public int compareTo(final KVersion other) {
            int res = Integer.compare(this.major, other.major);
            if (res == 0) {
                res = Integer.compare(this.minor, other.minor);
            }
            if (res == 0) {
                res = Integer.compare(this.sub, other.sub);
            }
            return res;
        }

        /**
         * At least satisfied with the given version.
         *
         * @param  from the start version to compare
         * @return return true if this version is at least satisfied with the given version.
         *         otherwise, return false.
         */
        public boolean isAtLeast(final KVersion from) {
            return compareTo(from) >= 0;
        }

        /**
         * Falls within the given range [from, to).
         *
         * @param  from the start version to compare
         * @param  to   the end version to compare
         * @return return true if this version falls within the given range.
         *         otherwise, return false.
         */
        public boolean isInRange(final KVersion from, final KVersion to) {
            return isAtLeast(from) && !isAtLeast(to);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof KVersion)) return false;
            KVersion that = (KVersion) o;
            return this.major == that.major
                    && this.minor == that.minor
                    && this.sub == that.sub;
        }
    };

    /**
     * Get a two-part kernel version number (major and minor) from a given string.
     *
     * TODO: use class KVersion.
     */
    private static Pair<Integer, Integer> getMajorMinorVersion(String version) {
        // Only gets major and minor number of the version string.
        final Pattern versionPattern = Pattern.compile("^(\\d+)(\\.(\\d+))?.*");
        final Matcher m = versionPattern.matcher(version);
        if (m.matches()) {
            final int major = Integer.parseInt(m.group(1));
            final int minor = TextUtils.isEmpty(m.group(3)) ? 0 : Integer.parseInt(m.group(3));
            return new Pair<>(major, minor);
        } else {
            return new Pair<>(0, 0);
        }
    }

    /**
     * Compares two version strings numerically. Compare only major and minor number of the
     * version string. The version comparison uses #Integer.compare. Possible version
     * 5, 5.10, 5-beta1, 4.8-RC1, 4.7.10.10 and so on.
     *
     * @param  s1 the first version string to compare
     * @param  s2 the second version string to compare
     * @return the value 0 if s1 == s2;
     *         a value less than 0 if s1 < s2 and
     *         a value greater than 0 if s1 > s2.
     *
     * TODO: use class KVersion.
     */
    public static int compareMajorMinorVersion(final String s1, final String s2) {
        final Pair<Integer, Integer> v1 = getMajorMinorVersion(s1);
        final Pair<Integer, Integer> v2 = getMajorMinorVersion(s2);

        if (Objects.equals(v1.first, v2.first)) {
            return Integer.compare(v1.second, v2.second);
        } else {
            return Integer.compare(v1.first, v2.first);
        }
    }

    /**
     * Get a three-part kernel version number (major, minor and subminor) from a given string.
     * Any version string must at least have major and minor number. If the subminor number can't
     * be parsed from string. Assign zero as subminor number. Invalid version is treated as
     * version 0.0.0.
     */
    public static KVersion getMajorMinorSubminorVersion(final String version) {
        // The kernel version is a three-part version number (major, minor and subminor). Get
        // the three-part version numbers and discard the remaining stuff if any.
        // For example:
        //   4.19.220-g500ede0aed22-ab8272303 --> 4.19.220
        //   5.17-rc6-g52099515ca00-ab8032400 --> 5.17.0
        final Pattern versionPattern = Pattern.compile("^(\\d+)\\.(\\d+)(\\.(\\d+))?.*");
        final Matcher m = versionPattern.matcher(version);
        if (m.matches()) {
            final int major = Integer.parseInt(m.group(1));
            final int minor = Integer.parseInt(m.group(2));
            final int sub = TextUtils.isEmpty(m.group(4)) ? 0 : Integer.parseInt(m.group(4));
            return new KVersion(major, minor, sub);
        } else {
            return new KVersion(0, 0, 0);
        }
    }

    /**
     * Check if the current kernel version is at least satisfied with the given version.
     *
     * @param  version the start version to compare
     * @return return true if the current version is at least satisfied with the given version.
     *         otherwise, return false.
     */
    public static boolean isKernelVersionAtLeast(final String version) {
        final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
        final KVersion current = DeviceInfoUtils.getMajorMinorSubminorVersion(kernelVersion);
        final KVersion from = DeviceInfoUtils.getMajorMinorSubminorVersion(version);
        return current.isAtLeast(from);
    }
}