package edu.berkeley.cs.amplab.carat.android.storage; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.ref.WeakReference; import java.util.LinkedList; import java.util.List; import android.app.Application; import android.content.Context; import android.util.Log; import edu.berkeley.cs.amplab.carat.android.CaratApplication; import edu.berkeley.cs.amplab.carat.android.Constants; import edu.berkeley.cs.amplab.carat.android.sampling.SamplingLibrary; import edu.berkeley.cs.amplab.carat.thrift.HogBugReport; import edu.berkeley.cs.amplab.carat.thrift.HogsBugs; import edu.berkeley.cs.amplab.carat.thrift.Reports; public class CaratDataStorage { public static final String FILENAME = "carat-reports.dat"; public static final String BLACKLIST_FILE = "carat-blacklist.dat"; public static final String QUESTIONNAIRE_URL_FILE = "questionnaire-url.txt"; public static final String BLACKLIST_FRESHNESS = "carat-blacklist-freshness.dat"; public static final String QUICKHOGS_FRESHNESS = "carat-quickhogs-freshness.dat"; public static final String GLOBLIST_FILE = "carat-globlist.dat"; public static final String BUGFILE = "carat-bugs.dat"; public static final String HOGFILE = "carat-hogs.dat"; public static final String SETTINGSFILE = "carat-settings.dat"; public static final String SAMPLES_REPORTED = "carat-samples-reported.dat"; public static final String FRESHNESS = "carat-freshness.dat"; private Application a = null; private long freshness = 0; private long blacklistFreshness = 0; private long quickHogsFreshness = 0; private long samples_reported = 0; private String questionnaireUrl = null; private WeakReference<Reports> caratData = null; private WeakReference<SimpleHogBug[]> bugData = null; private WeakReference<SimpleHogBug[]> hogData = null; private WeakReference<SimpleHogBug[]> settingsData = null; private WeakReference<List<String>> blacklistedApps = null; private WeakReference<List<String>> blacklistedGlobs = null; public CaratDataStorage(Application a) { this.a = a; freshness = readFreshness(); blacklistFreshness = readBlacklistFreshness(); quickHogsFreshness = readQuickHogsFreshness(); caratData = new WeakReference<Reports>(readReports()); readBugReport(); readHogReport(); readBlacklist(); samples_reported = readSamplesReported(); } public void writeReports(Reports reports) { if (reports == null) return; caratData = new WeakReference<Reports>(reports); writeObject(reports, FILENAME); } public void writeFreshness() { freshness = System.currentTimeMillis(); writeText(freshness + "", FRESHNESS); } public void writeBlacklistFreshness() { blacklistFreshness = System.currentTimeMillis(); writeText(blacklistFreshness + "", BLACKLIST_FRESHNESS); } public void writeQuickHogsFreshness() { quickHogsFreshness = System.currentTimeMillis(); writeText(quickHogsFreshness + "", QUICKHOGS_FRESHNESS); } public void writeObject(Object o, String fname) { FileOutputStream fos = getFos(fname); if (fos == null) return; try { ObjectOutputStream dos = new ObjectOutputStream(fos); dos.writeObject(o); dos.close(); } catch (IOException e) { Log.e(this.getClass().getName(), "Could not write object:" + o + "!"); e.printStackTrace(); } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem writing object", th); } } public Object readObject(String fname) { FileInputStream fin = getFin(fname); if (fin == null) return null; try { ObjectInputStream din = new ObjectInputStream(fin); Object o = din.readObject(); din.close(); return o; } catch (IOException e) { Log.e(this.getClass().getName(), "Could not read object from " + fname + "!"); e.printStackTrace(); } catch (ClassNotFoundException e) { Log.e(this.getClass().getName(), "Could not find class: " + e.getMessage() + " reading from " + fname + "!"); e.printStackTrace(); } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem reading object", th); } return null; } public void writeText(String thing, String fname) { FileOutputStream fos = getFos(fname); if (fos == null) return; try { DataOutputStream dos = new DataOutputStream(fos); dos.writeUTF(thing); dos.close(); } catch (IOException e) { Log.e(this.getClass().getName(), "Could not write text:" + thing + "!"); e.printStackTrace(); } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem writing text in "+fname, th); } } public String readText(String fname) { FileInputStream fin = getFin(fname); if (fin == null) return null; try { DataInputStream din = new DataInputStream(fin); String s = din.readUTF(); din.close(); return s; } catch (IOException e) { Log.e(this.getClass().getName(), "Could not read text from " + fname + "!"); e.printStackTrace(); } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem reading text", th); } return null; } private FileInputStream getFin(String fname) { try { return a.openFileInput(fname); } catch (FileNotFoundException e) { Log.w(this.getClass().getName(), "File " + fname + " does not exist yet. Wait for reports."); // e.printStackTrace(); return null; } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem opening file "+fname+" for input", th); return null; } } private FileOutputStream getFos(String fname) { try { return a.openFileOutput(fname, Context.MODE_PRIVATE); } catch (FileNotFoundException e) { Log.w(this.getClass().getName(), "File " + fname + " does not exist yet. Wait for reports."); // e.printStackTrace(); return null; } catch (Throwable th){ Log.e(this.getClass().getName(), "Problem opening file "+fname+" for output", th); return null; } } public long readFreshness() { String s = readText(FRESHNESS); Log.d("CaratDataStorage", "Read freshness: " + s); if (s != null) return Long.parseLong(s); else return -1; } public Reports readReports() { Object o = readObject(FILENAME); Log.d("CaratDataStorage", "Read Reports: " + o); if (o != null) { caratData = new WeakReference<Reports>((Reports) o); return (Reports) o; } else return null; } /** * @return the freshness */ public long getFreshness() { return freshness; } public long readBlacklistFreshness() { String s = readText(BLACKLIST_FRESHNESS); Log.d("CaratDataStorage", "Read freshness: " + s); if (s != null) return Long.parseLong(s); else return -1; } public long getBlacklistFreshness() { return blacklistFreshness; } public long readQuickHogsFreshness() { String s = readText(QUICKHOGS_FRESHNESS); Log.d("CaratDataStorage", "Read freshness: " + s); if (s != null) return Long.parseLong(s); else return -1; } public long getQuickHogsFreshness() { return quickHogsFreshness; } /** * @return a list of blacklisted apps */ public List<String> getBlacklist() { if (blacklistedApps != null && blacklistedApps.get() != null) return blacklistedApps.get(); else return readBlacklist(); } /** * @return a list of blacklisted expressions */ public List<String> getGloblist() { if (blacklistedGlobs != null && blacklistedGlobs.get() != null) return blacklistedGlobs.get(); else return readGloblist(); } /** * * @return a list of blacklisted apps */ public List<String> readBlacklist() { Object o = readObject(BLACKLIST_FILE); //Log.d("CaratDataStorage", "Read blacklist: " + o); if (o != null) { blacklistedApps = new WeakReference<List<String>>((List<String>) o); return (List<String>) o; } else return null; } /** * * @param blacklist the list of blacklisted apps to write. */ public void writeBlacklist(List<String> blacklist) { if (blacklist == null) return; blacklistedApps = new WeakReference<List<String>>(blacklist); writeObject(blacklist, BLACKLIST_FILE); } /** * * @return a list of blacklisted expressions */ public List<String> readGloblist() { Object o = readObject(GLOBLIST_FILE); //Log.d("CaratDataStorage", "Read glob blacklist: " + o); if (o != null) { blacklistedGlobs = new WeakReference<List<String>>((List<String>) o); return (List<String>) o; } else return null; } /** * * @param globlist the list of blacklisted expressions to write. */ public void writeGloblist(List<String> globlist) { if (globlist == null) return; blacklistedGlobs = new WeakReference<List<String>>(globlist); writeObject(globlist, GLOBLIST_FILE); } /** * @return the questionnaire base URL, read from storage or memory. */ public String getQuestionnaireUrl() { if (questionnaireUrl != null) return questionnaireUrl; else return readQuestionnaireUrl(); } /** * * @return the questionnaire base URL, read from storage. */ public String readQuestionnaireUrl() { String url = readText(QUESTIONNAIRE_URL_FILE); //Log.d("CaratDataStorage", "Read blacklist: " + o); if (url != null) { return url; } else return null; } /** * Write questionnaire URL to permanent storage. * @param url the questionnaire base URL. */ public void writeQuestionnaireUrl(String url) { if (url == null) return; questionnaireUrl = url; writeText(url, QUESTIONNAIRE_URL_FILE); } public void samplesReported(int howmany) { samples_reported += howmany; writeText(samples_reported+ "", SAMPLES_REPORTED); } public long readSamplesReported() { String s = readText(SAMPLES_REPORTED); Log.d("CaratDataStorage", "Read samples reported: " + s); // here is the bug. s is null! if (s != null) return Long.parseLong(s); else return -1; } /** * @return the freshness */ public long getSamplesReported() { return samples_reported; } /** * @return the caratData */ public Reports getReports() { if (caratData != null && caratData.get() != null) return caratData.get(); else return readReports(); } /** * @return the bug reports */ public SimpleHogBug[] getBugReport() { if (bugData == null || bugData.get() == null) { readBugReport(); } if (bugData == null || bugData.get() == null) return null; return bugData.get(); } /** * @return the hog reports */ public SimpleHogBug[] getHogReport() { if (hogData == null || hogData.get() == null) { readHogReport(); } if (hogData == null || hogData.get() == null) return null; return hogData.get(); } public SimpleHogBug[] getSettingsReport() { if (settingsData == null || settingsData.get() == null) { readSettingsReport(); } if (settingsData == null || settingsData.get() == null) return null; return settingsData.get(); } public void writeBugReport(HogBugReport r) { if (r != null) { SimpleHogBug[] list = convertAndFilter(r.getHbList(), true); if (list != null){ bugData = new WeakReference<SimpleHogBug[]>(list); writeObject(list, BUGFILE); } } } public void writeHogReport(HogBugReport r) { if (r != null) { SimpleHogBug[] list = convertAndFilter(r.getHbList(), false); if (list != null){ hogData = new WeakReference<SimpleHogBug[]>(list); writeObject(list, HOGFILE); } } } public void writeSettingsReport(HogBugReport r) { if (r != null) { SimpleHogBug[] list = convertAndFilter(r.getHbList(), false); if (list != null){ settingsData = new WeakReference<SimpleHogBug[]>(list); writeObject(list, SETTINGSFILE); } } } /** * For Settings, we need more than a boolean here. * @param list the list of bugs or hogs received from the server. * @param isBug True if the list contains Bugs, false if Hogs. * @return The list of non-hidden bugs or hogs. */ private SimpleHogBug[] convertAndFilter(List<HogsBugs> list, boolean isBug) { if (list == null) return null; List<SimpleHogBug> result = new LinkedList<SimpleHogBug>(); int size = list.size(); for (int i = 0; i < size; ++i) { HogsBugs item = list.get(i); String n = fixName(item.getAppName()); if (SamplingLibrary.isHidden(CaratApplication.getContext(), n)) continue; SimpleHogBug h = new SimpleHogBug(n, isBug ? Constants.Type.BUG:Constants.Type.HOG); h.setAppLabel(item.getAppLabel()); String priority = item.getAppPriority(); if (priority == null || priority.length() == 0) priority = "Foreground app"; h.setAppPriority(priority); h.setExpectedValue(item.getExpectedValue()); h.setExpectedValueWithout(item.getExpectedValueWithout()); h.setwDistance(item.getWDistance()); //result[i].setxVals(convert(item.getXVals())); h.setError(item.getError()); h.setErrorWithout(item.getErrorWithout()); h.setSamples(item.getSamples()); h.setSamplesWithout(item.getSamplesWithout()); //result[i].setSignificance(item.getSignificance()); /*result[i].setyVals(convert(item.getYVals())); result[i].setxValsWithout(convert(item.getXValsWithout())); result[i].setyValsWithout(convert(item.getYValsWithout()));*/ result.add(h); } return result.toArray(new SimpleHogBug[result.size()]); } public static double[] convert(List<Double> dbls) { if (dbls == null) return new double[0]; for (int j = 0; j < dbls.size(); ++j) { if (dbls.get(j) == 0.0) { dbls.remove(j); j--; } } double[] arr = new double[dbls.size()]; for (int j = 0; j < dbls.size(); ++j) { arr[j] = dbls.get(j); } return arr; } private String fixName(String name) { if (name == null) return null; int idx = name.lastIndexOf(':'); if (idx <= 0) idx = name.length(); String n = name.substring(0, idx); return n; } public SimpleHogBug[] readBugReport() { Object o = readObject(BUGFILE); //Log.d("CaratDataStorage", "Read Bugs: " + o); if (o == null || !(o instanceof SimpleHogBug[])) return null; SimpleHogBug[] r = (SimpleHogBug[]) o; bugData = new WeakReference<SimpleHogBug[]>(r); return r; } public SimpleHogBug[] readHogReport() { Object o = readObject(HOGFILE); //Log.d("CaratDataStorage", "Read Hogs: " + o); if (o == null || !(o instanceof SimpleHogBug[])) return null; SimpleHogBug[] r = (SimpleHogBug[]) o; hogData = new WeakReference<SimpleHogBug[]>(r); return r; } public SimpleHogBug[] readSettingsReport() { Object o = readObject(SETTINGSFILE); if (o == null || !(o instanceof SimpleHogBug[])) return null; SimpleHogBug[] r = (SimpleHogBug[]) o; settingsData = new WeakReference<SimpleHogBug[]>(r); return r; } }