1 /* 2 * Copyright (C) 2015 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.settingslib; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ResolveInfo; 24 import android.os.Build; 25 import android.text.TextUtils; 26 import android.text.format.DateFormat; 27 import android.util.Log; 28 29 import java.io.BufferedReader; 30 import java.io.FileReader; 31 import java.io.IOException; 32 import java.text.ParseException; 33 import java.text.SimpleDateFormat; 34 import java.util.Date; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 40 public class DeviceInfoUtils { 41 private static final String TAG = "DeviceInfoUtils"; 42 43 private static final String FILENAME_PROC_VERSION = "/proc/version"; 44 private static final String FILENAME_MSV = "/sys/board_properties/soc/msv"; 45 46 /** 47 * Reads a line from the specified file. 48 * @param filename the file to read from 49 * @return the first line, if any. 50 * @throws IOException if the file couldn't be read 51 */ 52 private static String readLine(String filename) throws IOException { 53 BufferedReader reader = new BufferedReader(new FileReader(filename), 256); 54 try { 55 return reader.readLine(); 56 } finally { 57 reader.close(); 58 } 59 } 60 61 public static String getFormattedKernelVersion() { 62 try { 63 return formatKernelVersion(readLine(FILENAME_PROC_VERSION)); 64 } catch (IOException e) { 65 Log.e(TAG, "IO Exception when getting kernel version for Device Info screen", 66 e); 67 68 return "Unavailable"; 69 } 70 } 71 72 public static String formatKernelVersion(String rawKernelVersion) { 73 // Example (see tests for more): 74 // Linux version 3.0.31-g6fb96c9 (android-build (at) xxx.xxx.xxx.xxx.com) \ 75 // (gcc version 4.6.x-xxx 20120106 (prerelease) (GCC) ) #1 SMP PREEMPT \ 76 // Thu Jun 28 11:02:39 PDT 2012 77 78 final String PROC_VERSION_REGEX = 79 "Linux version (\\S+) " + /* group 1: "3.0.31-g6fb96c9" */ 80 "\\((\\S+?)\\) " + /* group 2: "x (at) y.com" (kernel builder) */ 81 "(?:\\(gcc.+? \\)) " + /* ignore: GCC version information */ 82 "(#\\d+) " + /* group 3: "#1" */ 83 "(?:.*?)?" + /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */ 84 "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 4: "Thu Jun 28 11:02:39 PDT 2012" */ 85 86 Matcher m = Pattern.compile(PROC_VERSION_REGEX).matcher(rawKernelVersion); 87 if (!m.matches()) { 88 Log.e(TAG, "Regex did not match on /proc/version: " + rawKernelVersion); 89 return "Unavailable"; 90 } else if (m.groupCount() < 4) { 91 Log.e(TAG, "Regex match on /proc/version only returned " + m.groupCount() 92 + " groups"); 93 return "Unavailable"; 94 } 95 return m.group(1) + "\n" + // 3.0.31-g6fb96c9 96 m.group(2) + " " + m.group(3) + "\n" + // x (at) y.com #1 97 m.group(4); // Thu Jun 28 11:02:39 PDT 2012 98 } 99 100 /** 101 * Returns " (ENGINEERING)" if the msv file has a zero value, else returns "". 102 * @return a string to append to the model number description. 103 */ 104 public static String getMsvSuffix() { 105 // Production devices should have a non-zero value. If we can't read it, assume it's a 106 // production device so that we don't accidentally show that it's an ENGINEERING device. 107 try { 108 String msv = readLine(FILENAME_MSV); 109 // Parse as a hex number. If it evaluates to a zero, then it's an engineering build. 110 if (Long.parseLong(msv, 16) == 0) { 111 return " (ENGINEERING)"; 112 } 113 } catch (IOException|NumberFormatException e) { 114 // Fail quietly, as the file may not exist on some devices, or may be unreadable 115 } 116 return ""; 117 } 118 119 public static String getFeedbackReporterPackage(Context context) { 120 final String feedbackReporter = 121 context.getResources().getString(R.string.oem_preferred_feedback_reporter); 122 if (TextUtils.isEmpty(feedbackReporter)) { 123 // Reporter not configured. Return. 124 return feedbackReporter; 125 } 126 // Additional checks to ensure the reporter is on system image, and reporter is 127 // configured to listen to the intent. Otherwise, dont show the "send feedback" option. 128 final Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 129 130 PackageManager pm = context.getPackageManager(); 131 List<ResolveInfo> resolvedPackages = 132 pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER); 133 for (ResolveInfo info : resolvedPackages) { 134 if (info.activityInfo != null) { 135 if (!TextUtils.isEmpty(info.activityInfo.packageName)) { 136 try { 137 ApplicationInfo ai = 138 pm.getApplicationInfo(info.activityInfo.packageName, 0); 139 if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 140 // Package is on the system image 141 if (TextUtils.equals( 142 info.activityInfo.packageName, feedbackReporter)) { 143 return feedbackReporter; 144 } 145 } 146 } catch (PackageManager.NameNotFoundException e) { 147 // No need to do anything here. 148 } 149 } 150 } 151 } 152 return null; 153 } 154 155 public static String getSecurityPatch() { 156 String patch = Build.VERSION.SECURITY_PATCH; 157 if (!"".equals(patch)) { 158 try { 159 SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd"); 160 Date patchDate = template.parse(patch); 161 String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy"); 162 patch = DateFormat.format(format, patchDate).toString(); 163 } catch (ParseException e) { 164 // broken parse; fall through and use the raw string 165 } 166 return patch; 167 } else { 168 return null; 169 } 170 } 171 172 } 173