1 /*
2  * Copyright (C) 2008 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 android.tests.getinfo;
18 
19 import android.app.Activity;
20 import android.app.ActivityManager;
21 import android.app.ActivityManager.MemoryInfo;
22 import android.app.Instrumentation;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.FeatureInfo;
26 import android.content.pm.PackageManager;
27 import android.content.res.Configuration;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.os.Environment;
31 import android.os.UserManager;
32 import android.os.SystemProperties;
33 import android.telephony.TelephonyManager;
34 import android.text.TextUtils;
35 import android.util.DisplayMetrics;
36 import android.util.Log;
37 import android.view.Display;
38 import android.view.WindowManager;
39 
40 import com.android.compatibility.common.util.ShellIdentityUtils;
41 
42 import java.io.IOException;
43 import java.lang.reflect.Field;
44 import java.lang.reflect.InvocationTargetException;
45 import java.lang.reflect.Method;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.HashSet;
49 import java.util.List;
50 import java.util.Scanner;
51 import java.util.Set;
52 
53 public class DeviceInfoInstrument extends Instrumentation implements DeviceInfoConstants {
54 
55     private static final String TAG = "DeviceInfoInstrument";
56 
57     private static Bundle mResults = new Bundle();
58 
DeviceInfoInstrument()59     public DeviceInfoInstrument() {
60         super();
61     }
62 
63     @Override
onCreate(Bundle arguments)64     public void onCreate(Bundle arguments) {
65         start();
66     }
67 
68     @Override
onStart()69     public void onStart() {
70         addResult(BUILD_ID, Build.ID);
71         addResult(PRODUCT_NAME, Build.PRODUCT);
72         addResult(BUILD_DEVICE, Build.DEVICE);
73         addResult(BUILD_BOARD, Build.BOARD);
74         addResult(BUILD_MANUFACTURER, Build.MANUFACTURER);
75         addResult(BUILD_BRAND, Build.BRAND);
76         addResult(BUILD_MODEL, Build.MODEL);
77         addResult(BUILD_TYPE, Build.TYPE);
78         addResult(BUILD_FINGERPRINT, Build.FINGERPRINT);
79         addResult(BUILD_ABI, Build.CPU_ABI);
80         addResult(BUILD_ABI2, Build.CPU_ABI2);
81         addResult(BUILD_ABIS, TextUtils.join(",", Build.SUPPORTED_ABIS));
82         addResult(BUILD_ABIS_32, TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS));
83         addResult(BUILD_ABIS_64, TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS));
84         addResult(SERIAL_NUMBER, Build.SERIAL);
85 
86         addResult(REFERENCE_BUILD_FINGERPRINT,
87             SystemProperties.get("ro.build.reference.fingerprint", ""));
88 
89         addResult(VERSION_RELEASE, Build.VERSION.RELEASE_OR_CODENAME);
90         addResult(VERSION_SDK, Build.VERSION.SDK);
91         addResult(VERSION_BASE_OS, Build.VERSION.BASE_OS);
92         addResult(VERSION_SECURITY_PATCH, Build.VERSION.SECURITY_PATCH);
93 
94         DisplayMetrics metrics = new DisplayMetrics();
95         WindowManager wm = (WindowManager) getContext().getSystemService(
96                 Context.WINDOW_SERVICE);
97         Display d = wm.getDefaultDisplay();
98         d.getRealMetrics(metrics);
99         addResult(RESOLUTION, String.format("%sx%s", metrics.widthPixels, metrics.heightPixels));
100         addResult(SCREEN_DENSITY, metrics.density);
101         addResult(SCREEN_X_DENSITY, metrics.xdpi);
102         addResult(SCREEN_Y_DENSITY, metrics.ydpi);
103 
104         String screenDensityBucket = getScreenDensityBucket(metrics);
105         addResult(SCREEN_DENSITY_BUCKET, screenDensityBucket);
106 
107         String screenSize = getScreenSize();
108         addResult(SCREEN_SIZE, screenSize);
109 
110         Configuration configuration = getContext().getResources().getConfiguration();
111         addResult(SMALLEST_SCREEN_WIDTH_DP, configuration.smallestScreenWidthDp);
112 
113         Intent intent = new Intent();
114         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
115         intent.setClass(this.getContext(), DeviceInfoActivity.class);
116 
117         DeviceInfoActivity activity = (DeviceInfoActivity) startActivitySync(intent);
118         waitForIdleSync();
119         activity.waitForAcitityToFinish();
120 
121         TelephonyManager tm = (TelephonyManager) getContext().getSystemService(
122                 Context.TELEPHONY_SERVICE);
123         // network
124         String network = tm.getNetworkOperatorName();
125         addResult(NETWORK, network.trim());
126         // imei
127         String imei = ShellIdentityUtils.invokeMethodWithShellPermissions(tm,
128                 (telephonyManager) -> telephonyManager.getDeviceId());
129         addResult(IMEI, imei);
130 
131         // imsi
132         String imsi = ShellIdentityUtils.invokeMethodWithShellPermissions(tm,
133                 (telephonyManager) -> telephonyManager.getSubscriberId());
134         addResult(IMSI, imsi);
135 
136         // phone number
137         String phoneNumber = tm.getLine1Number();
138         addResult(PHONE_NUMBER, phoneNumber);
139 
140         // features
141         String features = getFeatures();
142         addResult(FEATURES, features);
143 
144         // processes
145         String processes = getProcesses();
146         addResult(PROCESSES, processes);
147 
148         // OpenGL ES version
149         String openGlEsVersion = getOpenGlEsVersion();
150         addResult(OPEN_GL_ES_VERSION, openGlEsVersion);
151 
152         // partitions
153         String partitions = getPartitions();
154         addResult(PARTITIONS, partitions);
155 
156         // System libraries
157         String sysLibraries = getSystemLibraries();
158         addResult(SYS_LIBRARIES, sysLibraries);
159 
160         // Storage devices
161         addResult(STORAGE_DEVICES, getStorageDevices());
162 
163         // Multi-user support
164         addResult(MULTI_USER, getMultiUserInfo());
165 
166         // Encrypted
167         addResult(ENCRYPTED, getEncrypted());
168 
169         // Memory Info
170         addResult(IS_LOW_RAM_DEVICE, isLowRamDevice());
171         addResult(MEMORY_CLASS, getMemoryClass());
172         addResult(LARGE_MEMORY_CLASS, getLargeMemoryClass());
173         addResult(TOTAL_MEMORY, getTotalMemory());
174 
175         // CPU Info
176         addResult(AVAILABLE_PROCESSORS, Runtime.getRuntime().availableProcessors());
177 
178         finish(Activity.RESULT_OK, mResults);
179     }
180 
181     /**
182      * Add string result.
183      *
184      * @param key the string of the key name.
185      * @param value string value.
186      */
addResult(final String key, final String value)187     static void addResult(final String key, final String value){
188         mResults.putString(key, value);
189     }
190 
191     /**
192      * Add integer result.
193      *
194      * @param key the string of the key name.
195      * @param value integer value.
196      */
addResult(final String key, final int value)197     static void addResult(final String key, final int value){
198         mResults.putInt(key, value);
199     }
200 
201     /**
202      * Add float result.
203      *
204      * @param key the string of the key name.
205      * @param value float value.
206      */
addResult(final String key, final float value)207     static void addResult(final String key, final float value){
208         mResults.putFloat(key, value);
209     }
210 
getScreenSize()211     private String getScreenSize() {
212         Configuration config = getContext().getResources().getConfiguration();
213         int screenLayout = config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
214         String screenSize = String.format("0x%x", screenLayout);
215         switch (screenLayout) {
216             case Configuration.SCREENLAYOUT_SIZE_SMALL:
217                 screenSize = "small";
218                 break;
219 
220             case Configuration.SCREENLAYOUT_SIZE_NORMAL:
221                 screenSize = "normal";
222                 break;
223 
224             case Configuration.SCREENLAYOUT_SIZE_LARGE:
225                 screenSize = "large";
226                 break;
227 
228             case Configuration.SCREENLAYOUT_SIZE_XLARGE:
229                 screenSize = "xlarge";
230                 break;
231 
232             case Configuration.SCREENLAYOUT_SIZE_UNDEFINED:
233                 screenSize = "undefined";
234                 break;
235         }
236         return screenSize;
237     }
238 
getScreenDensityBucket(DisplayMetrics metrics)239     private String getScreenDensityBucket(DisplayMetrics metrics) {
240         switch (metrics.densityDpi) {
241             case DisplayMetrics.DENSITY_LOW:
242                 return "ldpi";
243 
244             case DisplayMetrics.DENSITY_MEDIUM:
245                 return "mdpi";
246 
247             case DisplayMetrics.DENSITY_TV:
248                 return "tvdpi";
249 
250             case DisplayMetrics.DENSITY_HIGH:
251                 return "hdpi";
252 
253             case DisplayMetrics.DENSITY_XHIGH:
254                 return "xdpi";
255 
256             default:
257                 return "" + metrics.densityDpi;
258         }
259     }
260 
261     /**
262      * Return a summary of the device's feature as a semi-colon-delimited list of colon separated
263      * name and availability pairs like "feature1:sdk:true;feature2:sdk:false;feature3:other:true;".
264      */
getFeatures()265     private String getFeatures() {
266         StringBuilder features = new StringBuilder();
267 
268         try {
269             Set<String> checkedFeatures = new HashSet<String>();
270 
271             PackageManager packageManager = getContext().getPackageManager();
272             for (String featureName : getPackageManagerFeatures()) {
273                 checkedFeatures.add(featureName);
274                 boolean hasFeature = packageManager.hasSystemFeature(featureName);
275                 addFeature(features, featureName, "sdk", hasFeature);
276             }
277 
278             FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
279             if (featureInfos != null) {
280                 for (FeatureInfo featureInfo : featureInfos) {
281                     if (featureInfo.name != null && !checkedFeatures.contains(featureInfo.name)) {
282                         addFeature(features, featureInfo.name, "other", true);
283                     }
284                 }
285             }
286         } catch (Exception exception) {
287             Log.e(TAG, "Error getting features: " + exception.getMessage(), exception);
288         }
289 
290         return features.toString();
291     }
292 
addFeature(StringBuilder features, String name, String type, boolean available)293     private static void addFeature(StringBuilder features, String name, String type,
294             boolean available) {
295         features.append(name).append(':').append(type).append(':').append(available).append(';');
296     }
297 
298     /**
299      * Use reflection to get the features defined by the SDK. If there are features that do not fit
300      * the convention of starting with "FEATURE_" then they will still be shown under the
301      * "Other Features" section.
302      *
303      * @return list of feature names from sdk
304      */
getPackageManagerFeatures()305     private List<String> getPackageManagerFeatures() {
306         try {
307             List<String> features = new ArrayList<String>();
308             Field[] fields = PackageManager.class.getFields();
309             for (Field field : fields) {
310                 if (field.getName().startsWith("FEATURE_")) {
311                     String feature = (String) field.get(null);
312                     features.add(feature);
313                 }
314             }
315             return features;
316         } catch (IllegalAccessException illegalAccess) {
317             throw new RuntimeException(illegalAccess);
318         }
319     }
320 
321     /**
322      * Return a semi-colon-delimited list of the root processes that were running on the phone
323      * or an error message.
324      */
getProcesses()325     private static String getProcesses() {
326         StringBuilder builder = new StringBuilder();
327 
328         try {
329             String[] rootProcesses = RootProcessScanner.getRootProcesses();
330             for (String rootProcess : rootProcesses) {
331                 builder.append(rootProcess).append(':').append(0).append(';');
332             }
333         } catch (Exception exception) {
334             Log.e(TAG, "Error getting processes: " + exception.getMessage(), exception);
335             builder.append(exception.getMessage());
336         }
337 
338         return builder.toString();
339     }
340 
341     /** @return a string containing the Open GL ES version number or an error message */
getOpenGlEsVersion()342     private String getOpenGlEsVersion() {
343         PackageManager packageManager = getContext().getPackageManager();
344         FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
345         if (featureInfos != null && featureInfos.length > 0) {
346             for (FeatureInfo featureInfo : featureInfos) {
347                 // Null feature name means this feature is the open gl es version feature.
348                 if (featureInfo.name == null) {
349                     return featureInfo.getGlEsVersion();
350                 }
351             }
352         }
353         return "No feature for Open GL ES version.";
354     }
355 
getPartitions()356     private String getPartitions() {
357         try {
358             StringBuilder builder = new StringBuilder();
359             Process df = new ProcessBuilder("df").start();
360             Scanner scanner = new Scanner(df.getInputStream());
361             try {
362                 while (scanner.hasNextLine()) {
363                     builder.append(scanner.nextLine()).append(';');
364                 }
365                 return builder.toString();
366             } finally {
367                 scanner.close();
368             }
369         } catch (IOException e) {
370             return "Not able to run df for partition information.";
371         }
372     }
373 
getSystemLibraries()374     private String getSystemLibraries() {
375         PackageManager pm = getContext().getPackageManager();
376         String list[] = pm.getSystemSharedLibraryNames();
377 
378         StringBuilder builder = new StringBuilder();
379         for (String lib : list) {
380             builder.append(lib);
381             builder.append(";");
382         }
383 
384         return builder.toString();
385     }
386 
getStorageDevices()387     private String getStorageDevices() {
388         int count = 0;
389         count = Math.max(count, getContext().getExternalCacheDirs().length);
390         count = Math.max(count, getContext().getExternalFilesDirs(null).length);
391         count = Math.max(
392                 count, getContext().getExternalFilesDirs(Environment.DIRECTORY_PICTURES).length);
393         count = Math.max(count, getContext().getObbDirs().length);
394 
395         if (Environment.isExternalStorageEmulated()) {
396             if (count == 1) {
397                 return "1 emulated";
398             } else {
399                 return "1 emulated, " + (count - 1) + " physical media";
400             }
401         } else {
402             return count + " physical media";
403         }
404     }
405 
getMultiUserInfo()406     private String getMultiUserInfo() {
407         try {
408             final Method method = UserManager.class.getMethod("getMaxSupportedUsers");
409             final Integer maxUsers = (Integer) method.invoke(null);
410             if (maxUsers == 1) {
411                 return "single user";
412             } else {
413                 return maxUsers + " users supported";
414             }
415         } catch (ClassCastException e) {
416         } catch (NoSuchMethodException e) {
417         } catch (InvocationTargetException e) {
418         } catch (IllegalAccessException e) {
419         }
420 
421         return "unknown";
422     }
423 
getProperty(String property)424     private static String getProperty(String property)
425             throws IOException {
426         Process process = new ProcessBuilder("getprop", property).start();
427         Scanner scanner = null;
428         String line = "";
429         try {
430             scanner = new Scanner(process.getInputStream());
431             line = scanner.nextLine();
432         } finally {
433             if (scanner != null) {
434                 scanner.close();
435             }
436         }
437         return line;
438     }
439 
getEncrypted()440     private int getEncrypted() {
441         try {
442             return "encrypted".equals(getProperty("ro.crypto.state")) ? 1 : 0;
443         } catch (IOException e) {
444         }
445 
446         return 0;
447     }
448 
isLowRamDevice()449     private String isLowRamDevice() {
450         ActivityManager activityManager = (ActivityManager) getContext()
451                 .getSystemService(Context.ACTIVITY_SERVICE);
452         return activityManager.isLowRamDevice() ? "true" : "false";
453     }
454 
getMemoryClass()455     private String getMemoryClass() {
456         ActivityManager activityManager = (ActivityManager) getContext()
457                 .getSystemService(Context.ACTIVITY_SERVICE);
458         return String.valueOf(activityManager.getMemoryClass());
459     }
460 
getLargeMemoryClass()461     private String getLargeMemoryClass() {
462         ActivityManager activityManager = (ActivityManager) getContext()
463                 .getSystemService(Context.ACTIVITY_SERVICE);
464         return String.valueOf(activityManager.getLargeMemoryClass());
465     }
466 
getTotalMemory()467     private String getTotalMemory() {
468         ActivityManager activityManager = (ActivityManager) getContext()
469                 .getSystemService(Context.ACTIVITY_SERVICE);
470 
471         MemoryInfo memoryInfo = new MemoryInfo();
472         activityManager.getMemoryInfo(memoryInfo);
473         return String.valueOf(memoryInfo.totalMem);
474     }
475 }
476