package edu.berkeley.cs.amplab.carat.android.sampling; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.lang.ref.WeakReference; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.RSAPublicKey; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.TimeZone; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.ActivityManager.RunningServiceInfo; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.database.Cursor; import android.location.Criteria; import android.location.GpsStatus; import android.location.Location; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.SystemClock; import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.Secure; import android.provider.Settings.SettingNotFoundException; import android.telephony.CellLocation; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import com.flurry.android.FlurryAgent; import edu.berkeley.cs.amplab.carat.android.CaratApplication; import edu.berkeley.cs.amplab.carat.android.Constants; import edu.berkeley.cs.amplab.carat.thrift.BatteryDetails; import edu.berkeley.cs.amplab.carat.thrift.CallMonth; import edu.berkeley.cs.amplab.carat.thrift.CellInfo; import edu.berkeley.cs.amplab.carat.thrift.CpuStatus; import edu.berkeley.cs.amplab.carat.thrift.Feature; import edu.berkeley.cs.amplab.carat.thrift.NetworkDetails; import edu.berkeley.cs.amplab.carat.thrift.ProcessInfo; import edu.berkeley.cs.amplab.carat.thrift.Sample; /** * Library class for methods that obtain information about the phone that is * running Carat. * * @author Eemil Lagerspetz * */ public final class SamplingLibrary { private static final boolean collectSignatures = true; public static final String SIG_SENT = "sig-sent:"; public static final String SIG_SENT_256 = "sigs-sent:"; public static final String INSTALLED = "installed:"; public static final String REPLACED = "replaced:"; public static final String UNINSTALLED = "uninstalled:"; // Disabled or turned off applications will be scheduled for reporting using this prefix public static final String DISABLED = "disabled:"; private static final int READ_BUFFER_SIZE = 2 * 1024; // Network status constants public static String NETWORKSTATUS_DISCONNECTED = "disconnected"; public static String NETWORKSTATUS_DISCONNECTING = "disconnecting"; public static String NETWORKSTATUS_CONNECTED = "connected"; public static String NETWORKSTATUS_CONNECTING = "connecting"; // Network type constants public static String TYPE_UNKNOWN = "unknown"; // Data State constants public static String DATA_DISCONNECTED = NETWORKSTATUS_DISCONNECTED; public static String DATA_CONNECTING = NETWORKSTATUS_CONNECTING; public static String DATA_CONNECTED = NETWORKSTATUS_CONNECTED; public static String DATA_SUSPENDED = "suspended"; // Data Activity constants public static String DATA_ACTIVITY_NONE = "none"; public static String DATA_ACTIVITY_IN = "in"; public static String DATA_ACTIVITY_OUT = "out"; public static String DATA_ACTIVITY_INOUT = "inout"; public static String DATA_ACTIVITY_DORMANT = "dormant"; // Wifi State constants public static String WIFI_STATE_DISABLING = "disabling"; public static String WIFI_STATE_DISABLED = "disabled"; public static String WIFI_STATE_ENABLING = "enabling"; public static String WIFI_STATE_ENABLED = "enabled"; public static String WIFI_STATE_UNKNOWN = "unknown"; // Call state constants public static String CALL_STATE_IDLE = "idle"; public static String CALL_STATE_OFFHOOK = "offhook"; public static String CALL_STATE_RINGING = "ringing"; // Mobile network constants /* * we cannot find network types:EVDO_B,LTE,EHRPD,HSPAP from TelephonyManager * now */ public static String NETWORK_TYPE_UNKNOWN = "unknown"; public static String NETWORK_TYPE_GPRS = "gprs"; public static String NETWORK_TYPE_EDGE = "edge"; public static String NETWORK_TYPE_UMTS = "utms"; public static String NETWORK_TYPE_CDMA = "cdma"; public static String NETWORK_TYPE_EVDO_0 = "evdo_0"; public static String NETWORK_TYPE_EVDO_A = "evdo_a"; public static String NETWORK_TYPE_EVDO_B = "evdo_b"; public static String NETWORK_TYPE_1xRTT = "1xrtt"; public static String NETWORK_TYPE_HSDPA = "hsdpa"; public static String NETWORK_TYPE_HSUPA = "hsupa"; public static String NETWORK_TYPE_HSPA = "hspa"; public static String NETWORK_TYPE_IDEN = "iden"; public static String NETWORK_TYPE_LTE = "lte"; public static String NETWORK_TYPE_EHRPD = "ehrpd"; public static String NETWORK_TYPE_HSPAP = "hspap"; private static final int EVDO_B = 12; private static final int LTE = 13; private static final int EHRPD = 14; private static final int HSPAP = 15; // Phone type constants public static String PHONE_TYPE_CDMA = "cdma"; public static String PHONE_TYPE_GSM = "gsm"; // public static String PHONE_TYPE_SIP="sip"; public static String PHONE_TYPE_NONE = "none"; public static double startLatitude = 0; public static double startLongitude = 0; public static double distance = 0; private static final String STAG = "getSample"; // private static final String TAG="FeaturesPowerConsumption"; public static final int UUID_LENGTH = 16; private static double lastBatteryLevel; private static double currentBatteryLevel; // we might not be able to read the current battery level at the first run // of Carat. // so it might be zero until we get the non-zero value from the intent // (BatteryManager.EXTRA_LEVEL & BatteryManager.EXTRA_SCALE) /** Library class, prevent instantiation */ private SamplingLibrary() { } /** * Returns a randomly generated unique identifier that stays constant for * the lifetime of the device. (May change if wiped). This is probably our * best choice for a UUID across the Android landscape, since it is present * on both phones and non-phones. * * @return a String that uniquely identifies this device. */ public static String getAndroidId(Context c) { return Secure.getString(c.getContentResolver(), Secure.ANDROID_ID); } public static String getUuid(Context c) { return getTimeBasedUuid(c, false); } public static String getTimeBasedUuid(Context c) { return getTimeBasedUuid(c, true); } public static double readLastBatteryLevel() { return lastBatteryLevel; } public static void setLastBatteryLevel(double level) { SamplingLibrary.lastBatteryLevel = level; } public static double getLastBatteryLevel(Context context) { return lastBatteryLevel; } public static double getCurrentBatteryLevel() { return currentBatteryLevel; } public static void setCurrentBatteryLevel(double level) { SamplingLibrary.currentBatteryLevel = level; } /** * * Take in currentLevel and scale as doubles to avoid loss of precision issues. * Note that Carat stores battery level as a value between 0 and 1, e.g. 0.45 for 45%. * @param currentLevel Current battery level, usually in percent. * @param scale Battery scale, usually 100.0. */ public static void setCurrentBatteryLevel(double currentLevel, double scale) { /* we should multiply the result of the division below by 100.0 to get the battery level * in the scale of 0-100, but since the previous samples in our server's dataset are in the scale of 0.00-1.00, * we omit the multiplication. */ double level = currentLevel / scale; /* * whenever we get these two arguments (extras from the intent: * EXTRA_LEVEL & EXTRA_SCALE), it doens't necessarily mean that a battery * percentage change has happened. Check the comments in the * broadcast receiver (sampler). */ if (level != getCurrentBatteryLevel()) { setCurrentBatteryLevel(level); // Log.d("SamplingLibrary.setCurrentBatteryLevel()", "currentBatteryLevel=" // + getCurrentBatteryLevel()); } } /** * Generate a time-based, random identifier. * * @param c * the app's Context * @return a time-based, random identifier. */ public static String getTimeBasedUuid(Context c, boolean includeTimestamp) { String aID = getAndroidId(c); String wifiMac = getWifiMacAddress(c); String devid = getDeviceId(c); String concat = ""; if (aID != null) concat = aID; else concat = "0000000000000000"; if (wifiMac != null) concat += wifiMac; else concat += "00:00:00:00:00:00"; // IMEI is 15 characters, decimal, while MEID is 14 characters, hex. Add // a space if length is less than 15: if (devid != null) { concat += devid; if (devid.length() < 15) concat += " "; } else concat += "000000000000000"; if (includeTimestamp) { long timestamp = System.currentTimeMillis(); concat += timestamp; } // Log.d(STAG, // "AID="+aID+" wifiMac="+wifiMac+" devid="+devid+" rawUUID=" +concat ); try { MessageDigest md = MessageDigest.getInstance("SHA-512"); md.update(concat.getBytes()); byte[] mdbytes = md.digest(); StringBuilder hexString = new StringBuilder(); for (int i = 0; i < mdbytes.length; i++) { String hx = Integer.toHexString(0xFF & mdbytes[i]); if (hx.equals("0")) hexString.append("00"); else hexString.append(hx); } String uuid = hexString.toString().substring(0, UUID_LENGTH); // FlurryAgent.logEvent("ANDROID_ID=" + aID +" UUID=" + uuid); return uuid; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return aID; } } /** * Returns the model of the device running Carat, for example "sdk" for the * emulator, Galaxy Nexus for Samsung Galaxy Nexus. * * @return the model of the device running Carat, for example "sdk" for the * emulator, Galaxy Nexus for Samsung Galaxy Nexus. */ public static String getModel() { return android.os.Build.MODEL; } /** * Returns the manufacturer of the device running Carat, for example * "google" or "samsung". * * @return the manufacturer of the device running Carat, for example * "google" or "samsung". */ public static String getManufacturer() { return android.os.Build.MANUFACTURER; } /** * Returns the OS version of the device running Carat, for example 2.3.3 or * 4.0.2. * * @return the OS version of the device running Carat, for example 2.3.3 or * 4.0.2. */ public static String getOsVersion() { return android.os.Build.VERSION.RELEASE; } /** * Returns the product name. * * @return the product name. */ public static String getProductName() { return android.os.Build.PRODUCT; } /** * Returns the kernel version, e.g. 3.4-1101. * * @return the kernel version, e.g. 3.4-1101. */ public static String getKernelVersion() { return System.getProperty("os.version", TYPE_UNKNOWN); } /** * Returns the build serial number. May only work for 2.3 and up. * * @return the build serial number. */ public static String getBuildSerial() { // return android.os.Build.Serial; return System.getProperty("ro.serial", TYPE_UNKNOWN); } /** * Print all system properties for debugging. * */ public static void printAllProperties() { Properties list = System.getProperties(); Enumeration<Object> keys = list.keys(); while (keys.hasMoreElements()) { String k = (String) keys.nextElement(); String v = list.getProperty(k); Log.d("PROPS", k + "=" + v); } } /** * Returns the brand for which the device is customized, e.g. Verizon. * * @return the brand for which the device is customized, e.g. Verizon. */ public static String getBrand() { return android.os.Build.BRAND; } /** * Return misc system details that we might want to use later. Currently * does nothing. * * @return */ public static Map<String, String> getSystemDetails() { Map<String, String> results = new HashMap<String, String>(); // TODO: Some of this should be added to registration to identify the // device and OS. // Cyanogenmod and others may have different kernels etc that affect // performance. /* * Log.d("SetModel", "board:" + android.os.Build.BOARD); * Log.d("SetModel", "bootloader:" + android.os.Build.BOOTLOADER); * Log.d("SetModel", "brand:" + android.os.Build.BRAND); * Log.d("SetModel", "CPU_ABI 1 and 2:" + android.os.Build.CPU_ABI + * ", " + android.os.Build.CPU_ABI2); Log.d("SetModel", "dev:" + * android.os.Build.DEVICE); Log.d("SetModel", "disp:" + * android.os.Build.DISPLAY); Log.d("SetModel", "FP:" + * android.os.Build.FINGERPRINT); Log.d("SetModel", "HW:" + * android.os.Build.HARDWARE); Log.d("SetModel", "host:" + * android.os.Build.HOST); Log.d("SetModel", "ID:" + * android.os.Build.ID); Log.d("SetModel", "manufacturer:" + * android.os.Build.MANUFACTURER); Log.d("SetModel", "prod:" + * android.os.Build.PRODUCT); Log.d("SetModel", "radio:" + * android.os.Build.RADIO); // FIXME: SERIAL not available on 2.2 // * Log.d("SetModel", "ser:" + android.os.Build.SERIAL); * Log.d("SetModel", "tags:" + android.os.Build.TAGS); Log.d("SetModel", * "time:" + android.os.Build.TIME); Log.d("SetModel", "type:" + * android.os.Build.TYPE); Log.d("SetModel", "unknown:" + * android.os.Build.UNKNOWN); Log.d("SetModel", "user:" + * android.os.Build.USER); Log.d("SetModel", "model:" + * android.os.Build.MODEL); Log.d("SetModel", "codename:" + * android.os.Build.VERSION.CODENAME); Log.d("SetModel", "release:" + * android.os.Build.VERSION.RELEASE); */ return results; } /** * Read memory information from /proc/meminfo. Return used, free, inactive, * and active memory. * * @return an int[] with used, free, inactive, and active memory, in kB, in * that order. */ public static int[] readMeminfo() { try { RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r"); String load = reader.readLine(); String[] toks = load.split("\\s+"); // Log.v("meminfo", "Load: " + load + " 1:" + toks[1]); int total = Integer.parseInt(toks[1]); load = reader.readLine(); toks = load.split("\\s+"); // Log.v("meminfo", "Load: " + load + " 1:" + toks[1]); int free = Integer.parseInt(toks[1]); load = reader.readLine(); load = reader.readLine(); load = reader.readLine(); load = reader.readLine(); toks = load.split("\\s+"); // Log.v("meminfo", "Load: " + load + " 1:" + toks[1]); int act = Integer.parseInt(toks[1]); load = reader.readLine(); toks = load.split("\\s+"); // Log.v("meminfo", "Load: " + load + " 1:" + toks[1]); int inact = Integer.parseInt(toks[1]); reader.close(); return new int[] { total - free, free, inact, act }; } catch (IOException ex) { ex.printStackTrace(); } return new int[] { 0, 0, 0, 0 }; } /** * Read memory usage using the public Android API methods in * ActivityManager, such as MemoryInfo and getProcessMemoryInfo. * * @param c * the Context from the running Activity. * @return int[] with total and used memory, in kB, in that order. */ public static int[] readMemory(Context c) { ActivityManager man = (ActivityManager) c.getSystemService(Activity.ACTIVITY_SERVICE); /* Get available (free) memory */ ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo(); man.getMemoryInfo(info); int totalMem = (int) info.availMem; /* Get memory used by all running processes. */ /* Step 1: gather pids */ List<ActivityManager.RunningAppProcessInfo> procs = man.getRunningAppProcesses(); List<ActivityManager.RunningServiceInfo> servs = man.getRunningServices(Integer.MAX_VALUE); int[] pids = new int[procs.size() + servs.size()]; int i = 0; for (ActivityManager.RunningAppProcessInfo pinfo : procs) { pids[i] = pinfo.pid; i++; } for (ActivityManager.RunningServiceInfo pinfo : servs) { pids[i] = pinfo.pid; i++; } /* * Step 2: Sum up Pss values (weighted memory usage, taking into account * shared page usage) */ android.os.Debug.MemoryInfo[] mems = man.getProcessMemoryInfo(pids); int memUsed = 0; for (android.os.Debug.MemoryInfo mem : mems) { memUsed += mem.getTotalPss(); } Log.v("Mem", "Total mem:" + totalMem); Log.v("Mem", "Mem Used:" + memUsed); return new int[] { totalMem, memUsed }; } // FIXME: Describe this. Why are there so many fields? Why is it divided by // 100? /* * The value of HZ varies across kernel versions and hardware platforms. On * i386 the situation is as follows: on kernels up to and including 2.4.x, * HZ was 100, giving a jiffy value of 0.01 seconds; starting with 2.6.0, HZ * was raised to 1000, giving a jiffy of 0.001 seconds. Since kernel 2.6.13, * the HZ value is a kernel configuration parameter and can be 100, 250 (the * default) or 1000, yielding a jiffies value of, respectively, 0.01, 0.004, * or 0.001 seconds. Since kernel 2.6.20, a further frequency is available: * 300, a number that divides evenly for the common video frame rates (PAL, * 25 HZ; NTSC, 30 HZ). * * I will leave the unit of cpu time as the jiffy and we can discuss later. * * 0 name of cpu 1 space 2 user time 3 nice time 4 sys time 5 idle time(it * is not include in the cpu total time) 6 iowait time 7 irg time 8 softirg * time * * the idleTotal[5] is the idle time which always changes. There are two * spaces between cpu and user time.That is a tricky thing and messed up * splitting.:) */ /** * Read CPU usage from /proc/stat, return a fraction of * usage/(usage+idletime) * * @return a fraction of usage/(usage+idletime) */ public static long[] readUsagePoint() { try { RandomAccessFile reader = new RandomAccessFile("/proc/stat", "r"); String load = reader.readLine(); String[] toks = load.split(" "); long idle1 = Long.parseLong(toks[5]); long cpu1 = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4]) + Long.parseLong(toks[6]) + Long.parseLong(toks[7]) + Long.parseLong(toks[8]); reader.close(); return new long[] { idle1, cpu1 }; } catch (IOException ex) { ex.printStackTrace(); } return null; } /** * Calculate CPU usage between the cpu and idle time given at two time * points. * * @param then * @param now * @return */ public static double getUsage(long[] then, long[] now) { if (then == null || now == null || then.length < 2 || now.length < 2) return 0.0; double idleAndCpuDiff = (now[0] + now[1]) - (then[0] + then[1]); return (now[1] - then[1]) / idleAndCpuDiff; } private static WeakReference<List<RunningAppProcessInfo>> runningAppInfo = null; public static List<ProcessInfo> getRunningAppInfo(Context c) { List<RunningAppProcessInfo> runningProcs = getRunningProcessInfo(c); List<RunningServiceInfo> runningServices = getRunningServiceInfo(c); List<ProcessInfo> l = new ArrayList<ProcessInfo>(); if (runningProcs != null) { for (RunningAppProcessInfo pi : runningProcs) { if (pi == null) continue; ProcessInfo item = new ProcessInfo(); item.setImportance(CaratApplication.importanceString(pi.importance)); item.setPId(pi.pid); item.setPName(pi.processName); l.add(item); } } if (runningServices != null) { for (RunningServiceInfo pi : runningServices) { if (pi == null) continue; ProcessInfo item = new ProcessInfo(); item.setImportance(pi.foreground ? "Foreground app" : "Service"); item.setPId(pi.pid); item.setPName(pi.clientPackage); l.add(item); } } return l; } /** * Populate running process info into the runningAppInfo WeakReference list, and return its value. * @param context the Context * @return the value of the runningAppInfo WeakReference list after setting it. */ private static List<RunningAppProcessInfo> getRunningProcessInfo(Context context) { if (runningAppInfo == null || runningAppInfo.get() == null) { ActivityManager pActivityManager = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE); List<RunningAppProcessInfo> runningProcs = pActivityManager.getRunningAppProcesses(); /* * TODO: Is this the right thing to do? Remove part after ":" in * process names */ for (RunningAppProcessInfo i : runningProcs) { if (i != null && i.processName != null) { int idx = i.processName.lastIndexOf(':'); if (idx <= 0) idx = i.processName.length(); i.processName = i.processName.substring(0, idx); } } runningAppInfo = new WeakReference<List<RunningAppProcessInfo>>(runningProcs); } return runningAppInfo.get(); } /** * Returns a list of currently running Services. * @param c the Context. * @return Returns a list of currently running Services. */ public static List<RunningServiceInfo> getRunningServiceInfo(Context c) { ActivityManager pActivityManager = (ActivityManager) c.getSystemService(Activity.ACTIVITY_SERVICE); return pActivityManager.getRunningServices(0); } /** * Helper to query whether an application is currently running and its code has not been evicted from memory. * @param context the Context * @param appName the package name or process name of the application. * @return true if the application is running, false otherwise. */ public static boolean isRunning(Context context, String appName) { List<RunningAppProcessInfo> runningProcs = getRunningProcessInfo(context); for (RunningAppProcessInfo i : runningProcs) { if (i.processName.equals(appName) && i.importance != RunningAppProcessInfo.IMPORTANCE_EMPTY) return true; } return false; } public static boolean isSettingsSuggestion(Context context, String appName) { // TODO: fill in (if everything is a suggestion, and no need for checking at the client side, then remove this method) return true; } /** * Used to clear the runningAppInfo WeakReference list when Carat is paused, so that it is refreshed when the process list view is shown. */ public static void resetRunningProcessInfo() { runningAppInfo = null; } /** * package name to packageInfo map for quick querying. */ static WeakReference<Map<String, PackageInfo>> packages = null; /** * Returns true if an application should be hidden in the UI. Uses the blacklist downloaded from Carat servers. * @param c the Context * @param processName the process name * @return true if the process should be hidden from the user, usually because it is an unkillable application that belongs to the system. */ public static boolean isHidden(Context c, String processName) { boolean isSystem = isSystem(c, processName); boolean blocked = isDisabled(c, processName) || (isSystem && !isWhiteListed(c, processName)); return blocked || isBlacklisted(c, processName); } /** * We currently do not employ a whitelist, so this returns true iff isBlacklisted(c, processName) returns false and vice versa. * * @param c the Context. * @param processName the process name. * @return true iff isBlacklisted(c, processName) returns false and vice versa. */ private static boolean isWhiteListed(Context c, String processName) { return !isBlacklisted(c, processName); } /** * Returns true if the processName matches an intem on the blacklist downloaded from Carat servers. * * @param c the Context. * @param processName the process name. * @return true if the processName matches an intem on the blacklist downloaded from Carat servers. */ private static boolean isBlacklisted(Context c, String processName) { /* * Whitelist: Messaging, Voice Search, Bluetooth Share * * Blacklist: Key chain, google partner set up, package installer, * package access helper */ if (CaratApplication.storage != null) { List<String> blacklist = CaratApplication.storage.getBlacklist(); if (blacklist != null && blacklist.size() > 0 && processName != null && blacklist.contains(processName)) { return true; } blacklist = CaratApplication.storage.getGloblist(); if (blacklist != null && blacklist.size() > 0 && processName != null) { for (String glob : blacklist) { if (glob == null) continue; // something* if (glob.endsWith("*") && processName.startsWith(glob.substring(0, glob.length() - 1))) return true; // *something if (glob.startsWith("*") && processName.endsWith(glob.substring(1))) return true; } } } String label = CaratApplication.labelForApp(c, processName); if (processName != null && label != null && label.equals(processName)) { // Log.v("Hiding uninstalled", processName); return true; } // FlurryAgent.logEvent("Whitelisted "+processName + " \""+ label+"\""); return false; } /** * Returns true if the application is preinstalled on the device. * This usually means it is a system application, e.g. Key chain, google partner set up, package installer, package access helper. * We currently do not filter these out, because some of them are killable by the user, and not part of the core system, even if they are preinstalled on the device. * @param context the Context. * @param processName the process name. * @return true if the application is preinstalled on the device. */ private static boolean isSystem(Context context, String processName) { PackageInfo pak = getPackageInfo(context, processName); if (pak != null) { ApplicationInfo i = pak.applicationInfo; int flags = i.flags; boolean isSystemApp = (flags & ApplicationInfo.FLAG_SYSTEM) > 0; isSystemApp = isSystemApp || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) > 0; // Log.v(STAG, processName + " is System app? " + isSystemApp); return isSystemApp; } return false; } public static boolean isDisabled(Context c, String processName) { PackageManager pm = c.getPackageManager(); if (pm == null) return false; try { ApplicationInfo info = pm.getApplicationInfo(processName, 0); boolean disabled = !info.enabled; /* If an app is disabled, schedule it for sending with the next sample. * This is triggered in the UI, so the amount of times that an app being * disabled is sent is limited to the number of times the user refreshes Carat * between two analysis runs. Disabled applications will then be recorded by * the analysis, and not sent to the client when they ask for hogs/bugs after that. * Over time, Carat then follows users' Hogs and Bugs better, knowing which apps are * disabled. */ if (disabled) { Log.i(STAG, "DISABLED: " + processName); Editor e = PreferenceManager.getDefaultSharedPreferences(c.getApplicationContext()).edit(); e.putBoolean(SamplingLibrary.DISABLED + processName, true).commit(); } return disabled; } catch (NameNotFoundException e) { Log.d(STAG, "Could not find app info for: "+processName); } return false; } /** * Helper to ensure the WeakReferenced `packages` is populated. * * @param context * @return The content of `packages` or null in case of failure. */ private static Map<String, PackageInfo> getPackages(Context context) { List<android.content.pm.PackageInfo> packagelist = null; if (packages == null || packages.get() == null || packages.get().size() == 0) { Map<String, PackageInfo> mp = new HashMap<String, PackageInfo>(); PackageManager pm = context.getPackageManager(); if (pm == null) return null; try { if (collectSignatures) packagelist = pm.getInstalledPackages(PackageManager.GET_SIGNATURES | PackageManager.GET_PERMISSIONS); else packagelist = pm.getInstalledPackages(0); } catch (Throwable th) { // Forget about it... } if (packagelist == null) return null; for (PackageInfo pak : packagelist) { if (pak == null || pak.applicationInfo == null || pak.applicationInfo.processName == null) continue; mp.put(pak.applicationInfo.processName, pak); } packages = new WeakReference<Map<String, PackageInfo>>(mp); if (mp == null || mp.size() == 0) return null; return mp; } else { if (packages == null) return null; Map<String, PackageInfo> p = packages.get(); if (p == null || p.size() == 0) return null; return p; } } /** * Get info for a single package from the WeakReferenced packagelist. * * @param context * @param processName * The package to get info for. * @return info for a single package from the WeakReferenced packagelist. */ public static PackageInfo getPackageInfo(Context context, String processName) { Map<String, PackageInfo> mp = getPackages(context); if (mp == null || !mp.containsKey(processName)) return null; PackageInfo pak = mp.get(processName); return pak; } /** * Returns a list of installed packages on the device. Will be called for * the first Carat sample on a phone, to get signatures for the malware * detection project. Later on, single package information is got by * receiving the package installed intent. * * @param context * @param filterSystem * if true, exclude system packages. * @return a list of installed packages on the device. */ public static Map<String, ProcessInfo> getInstalledPackages(Context context, boolean filterSystem) { Map<String, PackageInfo> packageMap = getPackages(context); PackageManager pm = context.getPackageManager(); if (pm == null) return null; Map<String, ProcessInfo> result = new HashMap<String, ProcessInfo>(); for (Entry<String, PackageInfo> pentry : packageMap.entrySet()) { try { String pkg = pentry.getKey(); PackageInfo pak = pentry.getValue(); if (pak != null) { int vc = pak.versionCode; ApplicationInfo appInfo = pak.applicationInfo; String label = pm.getApplicationLabel(appInfo).toString(); // we need application UID to be able to use Android's // TrafficStat API // in order to get the traffic info of a particular app: int appUid = appInfo.uid; // get the amount of transmitted and received bytes by an // app // TODO: disabled for debugging // TrafficRecord trafficRecord = getAppTraffic(appUid); int flags = pak.applicationInfo.flags; // Check if it is a system app boolean isSystemApp = (flags & ApplicationInfo.FLAG_SYSTEM) > 0; isSystemApp = isSystemApp || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) > 0; if (filterSystem & isSystemApp) continue; if (pak.signatures.length > 0) { List<String> sigList = getSignatures(pak); ProcessInfo pi = new ProcessInfo(); pi.setPName(pkg); pi.setApplicationLabel(label); pi.setVersionCode(vc); pi.setPId(-1); pi.setIsSystemApp(isSystemApp); pi.setAppSignatures(sigList); pi.setImportance(Constants.IMPORTANCE_NOT_RUNNING); pi.setInstallationPkg(pm.getInstallerPackageName(pkg)); pi.setVersionName(pak.versionName); //TODO: disbaled for debugging // pi.setTrafficRecord(trafficRecord); result.put(pkg, pi); } } } catch (Throwable th) { // Forget about it... } } return result; } /** * Returns info about an installed package. Will be called when receiving * the PACKAGE_ADDED or PACKAGE_REPLACED intent. * * @param context * @param filterSystem * if true, exclude system packages. * @return a list of installed packages on the device. */ public static ProcessInfo getInstalledPackage(Context context, String pkg) { PackageManager pm = context.getPackageManager(); if (pm == null) return null; PackageInfo pak; try { pak = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES | PackageManager.GET_PERMISSIONS); } catch (NameNotFoundException e) { return null; } if (pak == null) return null; ProcessInfo pi = new ProcessInfo(); int vc = pak.versionCode; ApplicationInfo info = pak.applicationInfo; String label = pm.getApplicationLabel(info).toString(); int flags = pak.applicationInfo.flags; // Check if it is a system app boolean isSystemApp = (flags & ApplicationInfo.FLAG_SYSTEM) > 0; isSystemApp = isSystemApp || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) > 0; if (pak.signatures.length > 0) { List<String> sigList = getSignatures(pak); pi.setPName(pkg); pi.setApplicationLabel(label); pi.setVersionCode(vc); pi.setPId(-1); pi.setIsSystemApp(isSystemApp); pi.setAppSignatures(sigList); pi.setImportance(Constants.IMPORTANCE_NOT_RUNNING); pi.setInstallationPkg(pm.getInstallerPackageName(pkg)); pi.setVersionName(pak.versionName); } return pi; } /** * Returns a List of ProcessInfo objects, helper for getSample. * * @param context the Context. * @return a List of ProcessInfo objects, helper for getSample. */ private static List<ProcessInfo> getRunningProcessInfoForSample(Context context) { SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(context); // Reset list for each sample runningAppInfo = null; List<ProcessInfo> list = getRunningAppInfo(context); List<ProcessInfo> result = new ArrayList<ProcessInfo>(); PackageManager pm = context.getPackageManager(); // Collected in the same loop to save computation. int[] procMem = new int[list.size()]; Set<String> procs = new HashSet<String>(); boolean inst = p.getBoolean(Constants.PREFERENCE_SEND_INSTALLED_PACKAGES, true); Map<String, ProcessInfo> ipkg = null; if (inst) ipkg = getInstalledPackages(context, false); for (ProcessInfo pi : list) { String pname = pi.getPName(); if (ipkg != null && ipkg.containsKey(pname)) ipkg.remove(pname); procs.add(pname); ProcessInfo item = new ProcessInfo(); PackageInfo pak = getPackageInfo(context, pname); if (pak != null) { String ver = pak.versionName; int vc = pak.versionCode; item.setVersionName(ver); item.setVersionCode(vc); ApplicationInfo info = pak.applicationInfo; // Human readable label (if any) String label = pm.getApplicationLabel(info).toString(); if (label != null && label.length() > 0) item.setApplicationLabel(label); int flags = pak.applicationInfo.flags; // Check if it is a system app boolean isSystemApp = (flags & ApplicationInfo.FLAG_SYSTEM) > 0; isSystemApp = isSystemApp || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) > 0; item.setIsSystemApp(isSystemApp); /* * boolean sigSent = p.getBoolean(SIG_SENT_256 + pname, false); * if (collectSignatures && !sigSent && pak.signatures != null * && pak.signatures.length > 0) { List<String> sigList = * getSignatures(pak); boolean sigSentOld = * p.getBoolean(SIG_SENT + pname, false); if (sigSentOld) * p.edit().remove(SIG_SENT + pname); * p.edit().putBoolean(SIG_SENT_256 + pname, true).commit(); * item.setAppSignatures(sigList); } */ } item.setImportance(pi.getImportance()); item.setPId(pi.getPId()); item.setPName(pname); String installationSource = null; if (!pi.isSystemApp) { try { // Log.w(STAG, "Calling getInstallerPackageName with: " + // pname); installationSource = pm.getInstallerPackageName(pname); } catch (IllegalArgumentException iae) { Log.e(STAG, "Could not get installer for " + pname); } } if (installationSource == null) installationSource = "null"; item.setInstallationPkg(installationSource); // procMem[list.indexOf(pi)] = pi.getPId(); // FIXME: More fields will need to be added here, but ProcessInfo // needs to change. /* * uid lru */ // add to result result.add(item); } // Send installed packages if we were to do so. if (ipkg != null && ipkg.size() > 0) { result.addAll(ipkg.values()); p.edit().putBoolean(Constants.PREFERENCE_SEND_INSTALLED_PACKAGES, false).commit(); } // Go through the preferences and look for UNINSTALL, INSTALL and // REPLACE keys set by InstallReceiver. Set<String> ap = p.getAll().keySet(); SharedPreferences.Editor e = p.edit(); boolean edited = false; for (String pref : ap) { if (pref.startsWith(INSTALLED)) { String pname = pref.substring(INSTALLED.length()); boolean installed = p.getBoolean(pref, false); if (installed) { Log.i(STAG, "Installed:" + pname); ProcessInfo i = getInstalledPackage(context, pname); if (i != null) { i.setImportance(Constants.IMPORTANCE_INSTALLED); result.add(i); e.remove(pref); edited = true; } } } else if (pref.startsWith(REPLACED)) { String pname = pref.substring(REPLACED.length()); boolean replaced = p.getBoolean(pref, false); if (replaced) { Log.i(STAG, "Replaced:" + pname); ProcessInfo i = getInstalledPackage(context, pname); if (i != null) { i.setImportance(Constants.IMPORTANCE_REPLACED); result.add(i); e.remove(pref); edited = true; } } } else if (pref.startsWith(UNINSTALLED)) { String pname = pref.substring(UNINSTALLED.length()); boolean uninstalled = p.getBoolean(pref, false); if (uninstalled) { Log.i(STAG, "Uninstalled:" + pname); result.add(uninstalledItem(pname, pref, e)); edited = true; } } else if (pref.startsWith(DISABLED)) { String pname = pref.substring(DISABLED.length()); boolean disabled = p.getBoolean(pref, false); if (disabled) { Log.i(STAG, "Disabled app:" + pname); result.add(disabledItem(pname, pref, e)); edited = true; } } } if (edited) e.commit(); // FIXME: These are not used yet. /* * ActivityManager pActivityManager = (ActivityManager) context * .getSystemService(Activity.ACTIVITY_SERVICE); Debug.MemoryInfo[] * memoryInfo = pActivityManager .getProcessMemoryInfo(procMem); for * (Debug.MemoryInfo info : memoryInfo) { // Decide which ones of info.* * we want, add to a new and improved // ProcessInfo object // FIXME: * Not used yet, Sample needs more fields // FIXME: Which memory fields * to choose? //int memory = info.dalvikPrivateDirty; } */ return result; } /** * Helper to set application to the uninstalled state in the Carat sample. * @param pname the package that was uninstalled. * @param pref The preference that stored the uninstallation directive. This preference will be deleted to ensure uninstallations are not sent multiple times. * @param e the Editor (passed and not created here for efficiency) * @return a new ProcessInfo entry describing the uninstalled item. */ private static ProcessInfo uninstalledItem(String pname, String pref, SharedPreferences.Editor e) { ProcessInfo item = new ProcessInfo(); item.setPName(pname); List<String> sigs = new LinkedList<String>(); sigs.add("uninstalled"); item.setAppSignatures(sigs); item.setPId(-1); item.setImportance(Constants.IMPORTANCE_UNINSTALLED); // Remember to remove it so we do not send // multiple uninstall events e.remove(pref); return item; } /** * Helper to set application to the disabled state in the Carat sample. * @param pname the package that was disabled. * @param pref The preference that stored the disabled directive. This preference will be deleted to ensure disabled apps are not sent multiple times. * @param e the Editor (passed and not created here for efficiency) * @return a new ProcessInfo entry describing the uninstalled item. */ private static ProcessInfo disabledItem(String pname, String pref, SharedPreferences.Editor e) { ProcessInfo item = new ProcessInfo(); item.setPName(pname); item.setPId(-1); item.setImportance(Constants.IMPORTANCE_DISABLED); // Remember to remove it so we do not send // multiple uninstall events e.remove(pref); return item; } /** * Depratecated, use int[] meminfo = readMemInfo(); int totalMemory = * meminfo[0] + meminfo[1]; */ @Deprecated public static String getMemoryInfo() { String tmp = null; BufferedReader br = null; try { File file = new File("/proc/meminfo"); FileInputStream in = new FileInputStream(file); br = new BufferedReader(new InputStreamReader(in), READ_BUFFER_SIZE); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { tmp = br.readLine(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } StringBuilder sMemory = new StringBuilder(); sMemory.append(tmp); try { tmp = br.readLine(); br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } sMemory.append("\n").append(tmp).append("\n"); String result = "Memery Status:\n" + sMemory; return result; } /* * Deprecated, use readMemInfo()[1] */ @Deprecated public static String getMemoryFree() { String tmp = null; BufferedReader br = null; try { File file = new File("/proc/meminfo"); FileInputStream in = new FileInputStream(file); br = new BufferedReader(new InputStreamReader(in), READ_BUFFER_SIZE); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { tmp = br.readLine(); tmp = br.readLine(); if (tmp != null) { // split by whitespace and take 2nd element, so that in: // MemoryFree: x kb // the x remains. String[] arr = tmp.split("\\s+"); if (arr.length > 1) tmp = arr[1]; } br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return tmp; } /** * Return time in seconds since last boot. */ public static double getUptime() { long uptime = SystemClock.elapsedRealtime(); /* * int seconds = (int) (uptime / 1000) % 60; int minutes = (int) (uptime * / (1000 * 60) % 60); int hours = (int) (uptime / (1000 * 60 * 60) % * 24); String tmp = "\nThe uptime is :" + hours + "hr:" + minutes + * "mins:" + seconds + "sec.\n"; return tmp; */ Log.v("uptime", String.valueOf(uptime)); return uptime / 1000.0; } /** * Get the network status, one of connected, disconnected, connecting, or disconnecting. * @param context the Context. * @return the network status, one of connected, disconnected, connecting, or disconnecting. */ public static String getNetworkStatus(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm == null) return NETWORKSTATUS_DISCONNECTED; NetworkInfo i = cm.getActiveNetworkInfo(); if (i == null) return NETWORKSTATUS_DISCONNECTED; NetworkInfo.State s = i.getState(); if (s == NetworkInfo.State.CONNECTED) return NETWORKSTATUS_CONNECTED; if (s == NetworkInfo.State.DISCONNECTED) return NETWORKSTATUS_DISCONNECTED; if (s == NetworkInfo.State.CONNECTING) return NETWORKSTATUS_CONNECTING; if (s == NetworkInfo.State.DISCONNECTING) return NETWORKSTATUS_DISCONNECTING; else return NETWORKSTATUS_DISCONNECTED; } /** * Get the network type, for example Wifi, mobile, wimax, or none. * * @param context * @return */ public static String getNetworkType(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (cm == null) return TYPE_UNKNOWN; NetworkInfo i = cm.getActiveNetworkInfo(); if (i == null) return TYPE_UNKNOWN; return i.getTypeName(); } /** * Returns true if the Internet is reachable. * @param c the Context * @return true if the Internet is reachable. */ public static boolean networkAvailable(Context c) { String network = getNetworkStatus(c); return network.equals(NETWORKSTATUS_CONNECTED); } /* Get current WiFi signal Strength */ public static int getWifiSignalStrength(Context context) { WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo myWifiInfo = myWifiManager.getConnectionInfo(); int wifiRssi = myWifiInfo.getRssi(); // Log.v("WifiRssi", "Rssi:" + wifiRssi); return wifiRssi; } /** * Get Wifi MAC ADDR. Hashed and used in UUID calculation. */ private static String getWifiMacAddress(Context context) { WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (myWifiManager == null) return null; WifiInfo myWifiInfo = myWifiManager.getConnectionInfo(); if (myWifiInfo == null) return null; return myWifiInfo.getMacAddress(); } /* Get current WiFi link speed */ public static int getWifiLinkSpeed(Context context) { WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo myWifiInfo = myWifiManager.getConnectionInfo(); int linkSpeed = myWifiInfo.getLinkSpeed(); // Log.v("linkSpeed", "Link speed:" + linkSpeed); return linkSpeed; } /* Check whether WiFi is enabled */ public static boolean getWifiEnabled(Context context) { boolean wifiEnabled = false; WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); wifiEnabled = myWifiManager.isWifiEnabled(); // Log.v("WifiEnabled", "Wifi is enabled:" + wifiEnabled); return wifiEnabled; } /* Get Wifi state: */ public static String getWifiState(Context context) { WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); int wifiState = myWifiManager.getWifiState(); switch (wifiState) { case WifiManager.WIFI_STATE_DISABLED: return WIFI_STATE_DISABLED; case WifiManager.WIFI_STATE_DISABLING: return WIFI_STATE_DISABLING; case WifiManager.WIFI_STATE_ENABLED: return WIFI_STATE_ENABLED; case WifiManager.WIFI_STATE_ENABLING: return WIFI_STATE_ENABLING; default: return WIFI_STATE_UNKNOWN; } } public static WifiInfo getWifiInfo(Context context) { WifiManager myWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiInfo connectionInfo = myWifiManager.getConnectionInfo(); // Log.v("WifiInfo", "Wifi information:" + connectionInfo); return connectionInfo; } /* * This method is deprecated. As of ICE_CREAM_SANDWICH, availability of * background data depends on several combined factors, and this method will * always return true. Instead, when background data is unavailable, * getActiveNetworkInfo() will now appear disconnected. */ /* Check whether background data are enabled */ @Deprecated public static boolean getBackgroundDataEnabled(Context context) { boolean bacDataEnabled = false; try { if (Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.BACKGROUND_DATA) == 1) { bacDataEnabled = true; } } catch (SettingNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Log.v("BackgroundDataEnabled", "Background data enabled? " + // bacDataEnabled); // return bacDataEnabled; return true; } /* Get Current Screen Brightness Value */ public static int getScreenBrightness(Context context) { int screenBrightnessValue = 0; try { screenBrightnessValue = android.provider.Settings.System.getInt(context.getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS); } catch (SettingNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Log.v("ScreenBrightness", "Screen brightness value:" + // screenBrightnessValue); return screenBrightnessValue; } public static boolean isAutoBrightness(Context context) { boolean autoBrightness = false; try { autoBrightness = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; } catch (SettingNotFoundException e) { e.printStackTrace(); } // Log.v("AutoScreenBrightness", // "Automatic Screen brightness mode is enabled:" + autoBrightness); return autoBrightness; } /* Check whether GPS are enabled */ public static boolean getGpsEnabled(Context context) { boolean gpsEnabled = false; LocationManager myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); gpsEnabled = myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); // Log.v("GPS", "GPS is :" + gpsEnabled); return gpsEnabled; } /* check the GSM cell information */ public static CellInfo getCellInfo(Context context) { CellInfo curCell = new CellInfo(); TelephonyManager myTelManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); String netOperator = myTelManager.getNetworkOperator(); // Fix crash when not connected to network (airplane mode, underground, // etc) if (netOperator == null || netOperator.length() < 3) { return curCell; } /* * FIXME: Actually check for mobile network status == connected before * doing this stuff. */ if (SamplingLibrary.getPhoneType(context) == PHONE_TYPE_CDMA) { CdmaCellLocation cdmaLocation = (CdmaCellLocation) myTelManager.getCellLocation(); if (cdmaLocation == null) { // Log.v("cdmaLocation", "CDMA Location:" + cdmaLocation); } else { int cid = cdmaLocation.getBaseStationId(); int lac = cdmaLocation.getNetworkId(); int mnc = cdmaLocation.getSystemId(); int mcc = Integer.parseInt(netOperator.substring(0, 3)); curCell.CID = cid; curCell.LAC = lac; curCell.MNC = mnc; curCell.MCC = mcc; curCell.radioType = SamplingLibrary.getMobileNetworkType(context); // Log.v("MCC", "MCC is:" + mcc); // Log.v("MNC", "MNC is:" + mnc); // Log.v("CID", "CID is:" + cid); // Log.v("LAC", "LAC is:" + lac); } } else if (SamplingLibrary.getPhoneType(context) == PHONE_TYPE_GSM) { GsmCellLocation gsmLocation = (GsmCellLocation) myTelManager.getCellLocation(); if (gsmLocation == null) { // Log.v("gsmLocation", "GSM Location:" + gsmLocation); } else { int cid = gsmLocation.getCid(); int lac = gsmLocation.getLac(); int mcc = Integer.parseInt(netOperator.substring(0, 3)); int mnc = Integer.parseInt(netOperator.substring(3)); curCell.MCC = mcc; curCell.MNC = mnc; curCell.LAC = lac; curCell.CID = cid; curCell.radioType = SamplingLibrary.getMobileNetworkType(context); // Log.v("MCC", "MCC is:" + mcc); // Log.v("MNC", "MNC is:" + mnc); // Log.v("CID", "CID is:" + cid); // Log.v("LAC", "LAC is:" + lac); } } return curCell; } /** * Return distance between <code>lastKnownLocation</code> and a newly * obtained location from any available provider. * * @param c * from Intent or Application. * @return */ public static double getDistance(Context c) { Location l = getLastKnownLocation(c); double distance = 0.0; if (lastKnownLocation != null && l != null) { distance = lastKnownLocation.distanceTo(l); } lastKnownLocation = l; return distance; } public static Location getLastKnownLocation(Context c) { String provider = getBestProvider(c); // FIXME: Some buggy device is giving GPS to us, even though we cannot // use it. if (provider != null && !provider.equals("gps")) { Location l = getLastKnownLocation(c, provider); return l; } return null; } private static Location getLastKnownLocation(Context context, String provider) { LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); Location l = lm.getLastKnownLocation(provider); return l; } /* Get the distance users between two locations */ public static double getDistance(double startLatitude, double startLongitude, double endLatitude, double endLongitude) { float[] results = new float[1]; Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, results); return results[0]; } /** * Return a list of enabled LocationProviders, such as GPS, Network, etc. * * @param context * from onReceive or app. * @return */ public static List<String> getEnabledLocationProviders(Context context) { LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); return lm.getProviders(true); } public static String getBestProvider(Context context) { LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); Criteria c = new Criteria(); c.setAccuracy(Criteria.ACCURACY_COARSE); c.setPowerRequirement(Criteria.POWER_LOW); String provider = lm.getBestProvider(c, true); return provider; } /* Check the maximum number of satellites can be used in the satellite list */ public static int getMaxNumSatellite(Context context) { LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); GpsStatus gpsStatus = locationManager.getGpsStatus(null); int maxNumSatellite = gpsStatus.getMaxSatellites(); // Log.v("maxNumStatellite", "Maxmium number of satellites:" + // maxNumSatellite); return maxNumSatellite; } /* Get call status */ public static String getCallState(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int callState = telManager.getCallState(); switch (callState) { case TelephonyManager.CALL_STATE_OFFHOOK: return CALL_STATE_OFFHOOK; case TelephonyManager.CALL_STATE_RINGING: return CALL_STATE_RINGING; default: return CALL_STATE_IDLE; } } private static String getDeviceId(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (telManager == null) return null; return telManager.getDeviceId(); } /* Get network type */ public static String getMobileNetworkType(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int netType = telManager.getNetworkType(); switch (netType) { case TelephonyManager.NETWORK_TYPE_1xRTT: return NETWORK_TYPE_1xRTT; case TelephonyManager.NETWORK_TYPE_CDMA: return NETWORK_TYPE_CDMA; case TelephonyManager.NETWORK_TYPE_EDGE: return NETWORK_TYPE_EDGE; case EHRPD: return NETWORK_TYPE_EHRPD; case TelephonyManager.NETWORK_TYPE_EVDO_0: return NETWORK_TYPE_EVDO_0; case TelephonyManager.NETWORK_TYPE_EVDO_A: return NETWORK_TYPE_EVDO_A; case EVDO_B: return NETWORK_TYPE_EVDO_B; case TelephonyManager.NETWORK_TYPE_GPRS: return NETWORK_TYPE_GPRS; case TelephonyManager.NETWORK_TYPE_HSDPA: return NETWORK_TYPE_HSDPA; case TelephonyManager.NETWORK_TYPE_HSPA: return NETWORK_TYPE_HSPA; case HSPAP: return NETWORK_TYPE_HSPAP; case TelephonyManager.NETWORK_TYPE_HSUPA: return NETWORK_TYPE_HSUPA; case TelephonyManager.NETWORK_TYPE_IDEN: return NETWORK_TYPE_IDEN; case LTE: return NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_UMTS: return NETWORK_TYPE_UMTS; default: // If we don't know the type, just return the number and let the // backend take care of it return netType + ""; } } /* Get Phone Type */ public static String getPhoneType(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int phoneType = telManager.getPhoneType(); switch (phoneType) { case TelephonyManager.PHONE_TYPE_CDMA: return PHONE_TYPE_CDMA; case TelephonyManager.PHONE_TYPE_GSM: return PHONE_TYPE_GSM; default: return PHONE_TYPE_NONE; } } /* Check is it network roaming */ public static boolean getRoamingStatus(Context context) { boolean roamStatus = false; TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); roamStatus = telManager.isNetworkRoaming(); // Log.v("RoamingStatus", "Roaming status:" + roamStatus); return roamStatus; } /* Get data state */ public static String getDataState(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int dataState = telManager.getDataState(); switch (dataState) { case TelephonyManager.DATA_CONNECTED: return DATA_CONNECTED; case TelephonyManager.DATA_CONNECTING: return DATA_CONNECTING; case TelephonyManager.DATA_DISCONNECTED: return DATA_DISCONNECTED; default: return DATA_SUSPENDED; } } /* Get data activity */ public static String getDataActivity(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int dataActivity = telManager.getDataActivity(); switch (dataActivity) { case TelephonyManager.DATA_ACTIVITY_IN: return DATA_ACTIVITY_IN; case TelephonyManager.DATA_ACTIVITY_OUT: return DATA_ACTIVITY_OUT; case TelephonyManager.DATA_ACTIVITY_INOUT: return DATA_ACTIVITY_INOUT; default: return DATA_ACTIVITY_NONE; } } /* Get the current location of the device */ public static CellLocation getDeviceLocation(Context context) { TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); CellLocation LocDevice = telManager.getCellLocation(); // Log.v("DeviceLocation", "Device Location:" + LocDevice); return LocDevice; } /** * Return a long[3] with incoming call time, outgoing call time, and * non-call time in seconds since boot. * * @param context * from onReceive or Activity * @return a long[3] with incoming call time, outgoing call time, and * non-call time in seconds since boot. */ public static long[] getCalltimesSinceBoot(Context context) { long[] result = new long[3]; long callInSeconds = 0; long callOutSeconds = 0; int type; long dur; // ms since boot long uptime = SystemClock.elapsedRealtime(); long now = System.currentTimeMillis(); long bootTime = now - uptime; String[] queries = new String[] { android.provider.CallLog.Calls.TYPE, android.provider.CallLog.Calls.DATE, android.provider.CallLog.Calls.DURATION }; Cursor cur = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, queries, android.provider.CallLog.Calls.DATE + " > " + bootTime, null, android.provider.CallLog.Calls.DATE + " ASC"); if (cur != null) { if (cur.moveToFirst()) { while (!cur.isAfterLast()) { type = cur.getInt(0); dur = cur.getLong(2); switch (type) { case android.provider.CallLog.Calls.INCOMING_TYPE: callInSeconds += dur; break; case android.provider.CallLog.Calls.OUTGOING_TYPE: callOutSeconds += dur; break; default: } cur.moveToNext(); } } else { Log.w("CallDurFromBoot", "No calls listed"); } cur.close(); } else { Log.w("CallDurFromBoot", "Cursor is null"); } // uptime is ms, so it needs to be divided by 1000 long nonCallTime = uptime / 1000 - callInSeconds - callOutSeconds; result[0] = callInSeconds; result[1] = callOutSeconds; result[2] = nonCallTime; return result; } /* Get a monthly call duration record */ public static Map<String, CallMonth> getMonthCallDur(Context context) { Map<String, CallMonth> callMonth = new HashMap<String, CallMonth>(); Map<String, String> callInDur = new HashMap<String, String>(); Map<String, String> callOutDur = new HashMap<String, String>(); int callType; long callDur; Date callDate; String tmpTime = null; String time; SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM"); CallMonth curMonth = null; String[] queryFields = new String[] { android.provider.CallLog.Calls.TYPE, android.provider.CallLog.Calls.DATE, android.provider.CallLog.Calls.DURATION }; Cursor myCursor = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, queryFields, null, null, android.provider.CallLog.Calls.DATE + " DESC"); if (myCursor.moveToFirst()) { for (int i = 0; i < myCursor.getColumnCount(); i++) { myCursor.moveToPosition(i); callType = myCursor.getInt(0); callDate = new Date(myCursor.getLong(1)); callDur = myCursor.getLong(2); time = dateformat.format(callDate); if (tmpTime != null && !time.equals(tmpTime)) { callMonth.put(tmpTime, curMonth); callInDur.clear(); callOutDur.clear(); curMonth = new CallMonth(); } tmpTime = time; if (callType == 1) { curMonth.tolCallInNum++; curMonth.tolCallInDur += callDur; callInDur.put("tolCallInNum", String.valueOf(curMonth.tolCallInNum)); callInDur.put("tolCallInDur", String.valueOf(curMonth.tolCallInDur)); } if (callType == 2) { curMonth.tolCallOutNum++; curMonth.tolCallOutDur += callDur; callOutDur.put("tolCallOutNum", String.valueOf(curMonth.tolCallOutNum)); callOutDur.put("tolCallOutDur", String.valueOf(curMonth.tolCallOutDur)); } if (callType == 3) { curMonth.tolMissedCallNum++; callInDur.put("tolMissedCallNum", String.valueOf(curMonth.tolMissedCallNum)); } } } else { // Log.v("MonthType", "callType=None"); // Log.v("MonthDate", "callDate=None"); // Log.v("MonthDuration", "callduration =None"); } return callMonth; } public static CallMonth getCallMonthinfo(Context context, String time) { Map<String, CallMonth> callInfo; callInfo = SamplingLibrary.getMonthCallDur(context); CallMonth call = new CallMonth(); call = callInfo.get(time); return call; } private static Location lastKnownLocation = null; /** * Get whether the screen is on or off. * * @return true if the screen is on. */ public static int isScreenOn(Context context) { android.os.PowerManager powerManager = (android.os.PowerManager) context .getSystemService(Context.POWER_SERVICE); if (powerManager != null) if (powerManager.isScreenOn()) return 1; return 0; } /** * Get the current timezone of the device. */ public static String getTimeZone(Context context) { Calendar cal = Calendar.getInstance(); TimeZone tz = cal.getTimeZone(); return tz.getDisplayName(); } /** * * @param context * @return true when app installation from unknown sources is enabled. */ public static int allowUnknownSources(Context context) { ContentResolver res = context.getContentResolver(); int unknownSources = Settings.Secure.getInt(res, Settings.Secure.INSTALL_NON_MARKET_APPS, 0); return unknownSources; } /** * * @param context * @return true when developer mode is enabled. */ public static int isDeveloperModeOn(Context context) { ContentResolver res = context.getContentResolver(); int adb = Settings.Secure.getInt(res, Settings.Secure.ADB_ENABLED, 0); // In API level 17, this is Settings.Global.ADB_ENABLED. return adb; } /* * TODO: Make the app running when the system reboots, and provide a stop * button. CPU and Memory info per application CPU core/ frequency, CPU * governors usage How to motivate user to upload more samples. */ /** * Safely terminate (kill) the given app. * * @param context * @param packageName * @param label * @return */ public static boolean killApp(Context context, String packageName, String label) { ActivityManager am = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE); if (am != null) { try { PackageInfo p = getPackageInfo(context, packageName); // Log.v(STAG, "Trying to kill proc=" + packageName + " pak=" + // p.packageName); FlurryAgent.logEvent("Killing app=" + (label == null ? "null" : label) + " proc=" + packageName + " pak=" + (p == null ? "null" : p.packageName)); am.killBackgroundProcesses(packageName); return true; } catch (Throwable th) { Log.e(STAG, "Could not kill process: " + packageName, th); } } return false; } private static String convertToHex(byte[] data) { StringBuilder buf = new StringBuilder(); for (byte b : data) { int halfbyte = (b >>> 4) & 0x0F; int two_halfs = 0; do { buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10))); halfbyte = b & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } public static Sample getSample(Context context, Intent intent, String lastBatteryState) { final String TAG = "SamplingLibrary.getSample"; Log.d(TAG, "getSample() was invoked."); String action = intent.getAction(); Log.d(TAG, "action = " + action); // Construct sample and return it in the end Sample mySample = new Sample(); SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(context); String uuId = p.getString(CaratApplication.getRegisteredUuid(), null); mySample.setUuId(uuId); mySample.setTriggeredBy(action); // required always long now = System.currentTimeMillis(); mySample.setTimestamp(now / 1000.0); // Record first data point for CPU usage long[] idleAndCpu1 = readUsagePoint(); // If the sampler is running because of the SCREEN_ON or SCREEN_OFF // event/action, // we want to get the info of all installed apps/packages, not only // those running. // This is because we need the traffic info of all apps, some might not // be running when // those events (screen on / screen off) occur // TODO: let's comment out these lines for debugging purpose // if (action.equals(Intent.ACTION_SCREEN_ON) || // action.equals(Intent.ACTION_SCREEN_OFF)) { // Log.d(TAG, // "the action has been Intent.ACTION_SCREEN_ON or SCREEN_OFF. Taking sample of ALL INSTALLED packages (rather than running processes)"); // Map<String, ProcessInfo> installedPackages = // getInstalledPackages(context, false); // List<ProcessInfo> processes = new ArrayList<ProcessInfo>(); // processes.addAll(installedPackages.values()); // } else { // Log.d(TAG, // "the action has NOT been Intent.ACTION_SCREEN_ON or SCREEN_OFF. Taking sample of running processes."); List<ProcessInfo> processes = getRunningProcessInfoForSample(context); mySample.setPiList(processes); // } int screenBrightness = SamplingLibrary.getScreenBrightness(context); mySample.setScreenBrightness(screenBrightness); boolean autoScreenBrightness = SamplingLibrary.isAutoBrightness(context); if (autoScreenBrightness) mySample.setScreenBrightness(-1); // Auto // boolean gpsEnabled = SamplingLibrary.getGpsEnabled(context); // Location providers List<String> enabledLocationProviders = SamplingLibrary.getEnabledLocationProviders(context); mySample.setLocationProviders(enabledLocationProviders); // TODO: not in Sample yet // int maxNumSatellite = SamplingLibrary.getMaxNumSatellite(context); String network = SamplingLibrary.getNetworkStatus(context); String networkType = SamplingLibrary.getNetworkType(context); String mobileNetworkType = SamplingLibrary.getMobileNetworkType(context); // Required in new Carat protocol if (network.equals(NETWORKSTATUS_CONNECTED)) { if (networkType.equals("WIFI")) mySample.setNetworkStatus(networkType); else mySample.setNetworkStatus(mobileNetworkType); } else mySample.setNetworkStatus(network); // String ns = mySample.getNetworkStatus(); // Log.d(STAG, "Set networkStatus="+ns); // Network details NetworkDetails nd = new NetworkDetails(); // Network type nd.setNetworkType(networkType); nd.setMobileNetworkType(mobileNetworkType); boolean roamStatus = SamplingLibrary.getRoamingStatus(context); nd.setRoamingEnabled(roamStatus); String dataState = SamplingLibrary.getDataState(context); nd.setMobileDataStatus(dataState); String dataActivity = SamplingLibrary.getDataActivity(context); nd.setMobileDataActivity(dataActivity); // Wifi stuff String wifiState = SamplingLibrary.getWifiState(context); nd.setWifiStatus(wifiState); int wifiSignalStrength = SamplingLibrary.getWifiSignalStrength(context); nd.setWifiSignalStrength(wifiSignalStrength); int wifiLinkSpeed = SamplingLibrary.getWifiLinkSpeed(context); nd.setWifiLinkSpeed(wifiLinkSpeed); // Add NetworkDetails substruct to Sample mySample.setNetworkDetails(nd); /* Calling Information */ // List<String> callInfo; // callInfo=SamplingLibrary.getCallInfo(context); /* Total call time */ // long totalCallTime=0; // totalCallTime=SamplingLibrary.getTotalCallDur(context); /* * long[] incomingOutgoingIdle = getCalltimesSinceBoot(context); * Log.d(STAG, "Call time since boot: Incoming=" + * incomingOutgoingIdle[0] + " Outgoing=" + incomingOutgoingIdle[1] + * " idle=" + incomingOutgoingIdle[2]); * * // Summary Call info CallInfo ci = new CallInfo(); String callState = * SamplingLibrary.getCallState(context); ci.setCallStatus(callState); * ci.setIncomingCallTime(incomingOutgoingIdle[0]); * ci.setOutgoingCallTime(incomingOutgoingIdle[1]); * ci.setNonCallTime(incomingOutgoingIdle[2]); * * mySample.setCallInfo(ci); */ // Bundle b = intent.getExtras(); int health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 0); int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0); // This is really an int. // FIXED: Not used yet, Sample needs more fields int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); String batteryTechnology = intent.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY); // FIXED: Not used yet, Sample needs more fields String batteryHealth = "Unknown"; String batteryStatus = "Unknown"; switch (health) { case BatteryManager.BATTERY_HEALTH_DEAD: batteryHealth = "Dead"; break; case BatteryManager.BATTERY_HEALTH_GOOD: batteryHealth = "Good"; break; case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: batteryHealth = "Over voltage"; break; case BatteryManager.BATTERY_HEALTH_OVERHEAT: batteryHealth = "Overheat"; break; case BatteryManager.BATTERY_HEALTH_UNKNOWN: batteryHealth = "Unknown"; break; case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: batteryHealth = "Unspecified failure"; break; } switch (status) { case BatteryManager.BATTERY_STATUS_CHARGING: batteryStatus = "Charging"; break; case BatteryManager.BATTERY_STATUS_DISCHARGING: batteryStatus = "Discharging"; break; case BatteryManager.BATTERY_STATUS_FULL: batteryStatus = "Full"; break; case BatteryManager.BATTERY_STATUS_NOT_CHARGING: batteryStatus = "Not charging"; break; case BatteryManager.BATTERY_STATUS_UNKNOWN: batteryStatus = "Unknown"; break; default: batteryStatus = lastBatteryState != null ? lastBatteryState : "Unknown"; } // FIXED: Not used yet, Sample needs more fields String batteryCharger = "unplugged"; switch (plugged) { case BatteryManager.BATTERY_PLUGGED_AC: batteryCharger = "ac"; break; case BatteryManager.BATTERY_PLUGGED_USB: batteryCharger = "usb"; break; } BatteryDetails bd = new BatteryDetails(); // otherInfo.setCPUIdleTime(totalIdleTime); // IMPORTANT: All of the battery details fields were never set (=always // zero), like the last battery level. // Now all must have been fixed. // current battery temperature in degrees Centigrade (the unit of the // temperature value // (returned by BatteryManager) is not Centigrade, it should be divided // by 10) int temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) / 10; bd.setBatteryTemperature(temperature); // otherInfo.setBatteryTemperature(temperature); // current battery voltage in VOLTS (the unit of the returned value by // BatteryManager is millivolts) double voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) / 1000; bd.setBatteryVoltage(voltage); // otherInfo.setBatteryVoltage(voltage); bd.setBatteryTechnology(batteryTechnology); bd.setBatteryCharger(batteryCharger); bd.setBatteryHealth(batteryHealth); mySample.setBatteryDetails(bd); mySample.setBatteryLevel(currentBatteryLevel); mySample.setBatteryState(batteryStatus); int[] usedFreeActiveInactive = SamplingLibrary.readMeminfo(); if (usedFreeActiveInactive != null && usedFreeActiveInactive.length == 4) { mySample.setMemoryUser(usedFreeActiveInactive[0]); mySample.setMemoryFree(usedFreeActiveInactive[1]); mySample.setMemoryActive(usedFreeActiveInactive[2]); mySample.setMemoryInactive(usedFreeActiveInactive[3]); } // TODO: Memory Wired should have memory that is "unevictable", that // will always be used even when all apps are killed // Log.d(STAG, "serial=" + getBuildSerial()); // Record second data point for cpu/idle time now = System.currentTimeMillis(); long[] idleAndCpu2 = readUsagePoint(); CpuStatus cs = new CpuStatus(); cs.setCpuUsage(getUsage(idleAndCpu1, idleAndCpu2)); cs.setUptime(getUptime()); mySample.setCpuStatus(cs); mySample.setDeveloperMode(isDeveloperModeOn(context)); mySample.setUnknownSources(allowUnknownSources(context)); mySample.setScreenOn(isScreenOn(context)); mySample.setTimeZone(getTimeZone(context)); // printAverageFeaturePower(context); // If there are extra fields, include them into the sample. List<Feature> extras = getExtras(context); if (extras != null && extras.size() > 0) mySample.setExtra(extras); return mySample; } /** * Helper method to collect all the extra information we wish to add to the sample into the Extra Feature list. * @param context the Context * @return a List<Feature> populated with extra items to collect outside of the protocol spec. */ private static List<Feature> getExtras(Context context) { LinkedList<Feature> res = new LinkedList<Feature>(); res.add(getVmVersion(context)); return res; } //TODO: disabled for debugging // private static TrafficRecord getAppTraffic(Integer uid) { // TrafficRecord trafficRecord = new TrafficRecord(); // trafficRecord.setTx(TrafficStats.getUidTxBytes(uid)); // trafficRecord.setRx(TrafficStats.getUidRxBytes(uid)); // return trafficRecord; // } /** * Get the java.vm.version system property as a Feature("vm", version). * @param context the Context. * @return a Feature instance with the key "vm" and value of the "java.vm.version" system property. */ private static Feature getVmVersion(Context context) { String vm = System.getProperty("java.vm.version"); if (vm == null) vm = ""; Feature vmVersion = new Feature(); vmVersion.setKey("vm"); vmVersion.setValue(vm); return vmVersion; } public static List<String> getSignatures(PackageInfo pak) { List<String> sigList = new LinkedList<String>(); String[] pmInfos = pak.requestedPermissions; if (pmInfos != null) { byte[] bytes = getPermissionBytes(pmInfos); String hexB = convertToHex(bytes); sigList.add(hexB); } Signature[] sigs = pak.signatures; for (Signature s : sigs) { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-1"); md.update(s.toByteArray()); byte[] dig = md.digest(); // Add SHA-1 sigList.add(convertToHex(dig)); CertificateFactory fac = CertificateFactory.getInstance("X.509"); if (fac == null) continue; X509Certificate cert = (X509Certificate) fac.generateCertificate(new ByteArrayInputStream(s .toByteArray())); if (cert == null) continue; PublicKey pkPublic = cert.getPublicKey(); if (pkPublic == null) continue; String al = pkPublic.getAlgorithm(); if (al.equals("RSA")) { md = MessageDigest.getInstance("SHA-256"); RSAPublicKey rsa = (RSAPublicKey) pkPublic; byte[] data = rsa.getModulus().toByteArray(); if (data[0] == 0) { byte[] copy = new byte[data.length - 1]; System.arraycopy(data, 1, copy, 0, data.length - 1); md.update(copy); } else md.update(data); dig = md.digest(); // Add SHA-256 of modulus sigList.add(convertToHex(dig)); } else if (al.equals("DSA")) { DSAPublicKey dsa = (DSAPublicKey) pkPublic; md = MessageDigest.getInstance("SHA-256"); byte[] data = dsa.getY().toByteArray(); if (data[0] == 0) { byte[] copy = new byte[data.length - 1]; System.arraycopy(data, 1, copy, 0, data.length - 1); md.update(copy); } else md.update(data); dig = md.digest(); // Add SHA-256 of public key (DSA) sigList.add(convertToHex(dig)); } else { Log.e("SamplingLibrary", "Weird algorithm: " + al + " for " + pak.packageName); } } catch (NoSuchAlgorithmException e) { // Do nothing } catch (CertificateException e) { // Do nothing } } return sigList; } public static byte[] getPermissionBytes(String[] perms) { if (perms == null) return null; if (permList.size() == 0) populatePermList(); // Log.i(STAG, "PermList Size: " + permList.size()); byte[] bytes = new byte[permList.size() / 8 + 1]; for (String p : perms) { int idx = permList.indexOf(p); if (idx > 0) { int i = idx / 8; idx = (int) Math.pow(2, idx - i * 8); bytes[i] = (byte) (bytes[i] | idx); } } return bytes; } private static final ArrayList<String> permList = new ArrayList<String>(); private static void populatePermList() { final String[] permArray = { "android.permission.ACCESS_CHECKIN_PROPERTIES", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS", "android.permission.ACCESS_MOCK_LOCATION", "android.permission.ACCESS_NETWORK_STATE", "android.permission.ACCESS_SURFACE_FLINGER", "android.permission.ACCESS_WIFI_STATE", "android.permission.ACCOUNT_MANAGER", "android.permission.AUTHENTICATE_ACCOUNTS", "android.permission.BATTERY_STATS", "android.permission.BIND_APPWIDGET", "android.permission.BIND_DEVICE_ADMIN", "android.permission.BIND_INPUT_METHOD", "android.permission.BIND_WALLPAPER", "android.permission.BLUETOOTH", "android.permission.BLUETOOTH_ADMIN", "android.permission.BRICK", "android.permission.BROADCAST_PACKAGE_REMOVED", "android.permission.BROADCAST_SMS", "android.permission.BROADCAST_STICKY", "android.permission.BROADCAST_WAP_PUSH", "android.permission.CALL_PHONE", "android.permission.CALL_PRIVILEGED", "android.permission.CAMERA", "android.permission.CHANGE_COMPONENT_ENABLED_STATE", "android.permission.CHANGE_CONFIGURATION", "android.permission.CHANGE_NETWORK_STATE", "android.permission.CHANGE_WIFI_MULTICAST_STATE", "android.permission.CHANGE_WIFI_STATE", "android.permission.CLEAR_APP_CACHE", "android.permission.CLEAR_APP_USER_DATA", "android.permission.CONTROL_LOCATION_UPDATES", "android.permission.DELETE_CACHE_FILES", "android.permission.DELETE_PACKAGES", "android.permission.DEVICE_POWER", "android.permission.DIAGNOSTIC", "android.permission.DISABLE_KEYGUARD", "android.permission.DUMP", "android.permission.EXPAND_STATUS_BAR", "android.permission.FACTORY_TEST", "android.permission.FLASHLIGHT", "android.permission.FORCE_BACK", "android.permission.GET_ACCOUNTS", "android.permission.GET_PACKAGE_SIZE", "android.permission.GET_TASKS", "android.permission.GLOBAL_SEARCH", "android.permission.HARDWARE_TEST", "android.permission.INJECT_EVENTS", "android.permission.INSTALL_LOCATION_PROVIDER", "android.permission.INSTALL_PACKAGES", "android.permission.INTERNAL_SYSTEM_WINDOW", "android.permission.INTERNET", "android.permission.KILL_BACKGROUND_PROCESSES", "android.permission.MANAGE_ACCOUNTS", "android.permission.MANAGE_APP_TOKENS", "android.permission.MASTER_CLEAR", "android.permission.MODIFY_AUDIO_SETTINGS", "android.permission.MODIFY_PHONE_STATE", "android.permission.MOUNT_FORMAT_FILESYSTEMS", "android.permission.MOUNT_UNMOUNT_FILESYSTEMS", "android.permission.PERSISTENT_ACTIVITY", "android.permission.PROCESS_OUTGOING_CALLS", "android.permission.READ_CALENDAR", "android.permission.READ_CONTACTS", "android.permission.READ_FRAME_BUFFER", "com.android.browser.permission.READ_HISTORY_BOOKMARKS", "android.permission.READ_INPUT_STATE", "android.permission.READ_LOGS", "android.permission.READ_OWNER_DATA", "android.permission.READ_PHONE_STATE", "android.permission.READ_SMS", "android.permission.READ_SYNC_SETTINGS", "android.permission.READ_SYNC_STATS", "android.permission.REBOOT", "android.permission.RECEIVE_BOOT_COMPLETED", "android.permission.RECEIVE_MMS", "android.permission.RECEIVE_SMS", "android.permission.RECEIVE_WAP_PUSH", "android.permission.RECORD_AUDIO", "android.permission.REORDER_TASKS", "android.permission.RESTART_PACKAGES", "android.permission.SEND_SMS", "android.permission.SET_ACTIVITY_WATCHER", "android.permission.SET_ALWAYS_FINISH", "android.permission.SET_ANIMATION_SCALE", "android.permission.SET_DEBUG_APP", "android.permission.SET_ORIENTATION", "android.permission.SET_PREFERRED_APPLICATIONS", "android.permission.SET_PROCESS_LIMIT", "android.permission.SET_TIME", "android.permission.SET_TIME_ZONE", "android.permission.SET_WALLPAPER", "android.permission.SET_WALLPAPER_HINTS", "android.permission.SIGNAL_PERSISTENT_PROCESSES", "android.permission.STATUS_BAR", "android.permission.SUBSCRIBED_FEEDS_READ", "android.permission.SUBSCRIBED_FEEDS_WRITE", "android.permission.SYSTEM_ALERT_WINDOW", "android.permission.UPDATE_DEVICE_STATS", "android.permission.USE_CREDENTIALS", "android.permission.VIBRATE", "android.permission.WAKE_LOCK", "android.permission.WRITE_APN_SETTINGS", "android.permission.WRITE_CALENDAR", "android.permission.WRITE_CONTACTS", "android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.WRITE_GSERVICES", "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", "android.permission.WRITE_OWNER_DATA", "android.permission.WRITE_SECURE_SETTINGS", "android.permission.WRITE_SETTINGS", "android.permission.WRITE_SMS", "android.permission.WRITE_SYNC_SETTINGS" }; for (String s : permArray) permList.add(s); } }