michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.background.healthreport; michael@0: michael@0: import org.json.JSONObject; michael@0: michael@0: import android.database.Cursor; michael@0: import android.util.SparseArray; michael@0: michael@0: /** michael@0: * Abstraction over storage for Firefox Health Report on Android. michael@0: */ michael@0: public interface HealthReportStorage { michael@0: // Right now we only care about the name of the field. michael@0: public interface MeasurementFields { michael@0: public class FieldSpec { michael@0: public final String name; michael@0: public final int type; michael@0: public FieldSpec(String name, int type) { michael@0: this.name = name; michael@0: this.type = type; michael@0: } michael@0: } michael@0: Iterable getFields(); michael@0: } michael@0: michael@0: public abstract class Field { michael@0: protected static final int UNKNOWN_TYPE_OR_FIELD_ID = -1; michael@0: michael@0: protected static final int FLAG_INTEGER = 1 << 0; michael@0: protected static final int FLAG_STRING = 1 << 1; michael@0: protected static final int FLAG_JSON = 1 << 2; michael@0: michael@0: protected static final int FLAG_DISCRETE = 1 << 8; michael@0: protected static final int FLAG_LAST = 1 << 9; michael@0: protected static final int FLAG_COUNTER = 1 << 10; michael@0: michael@0: protected static final int FLAG_COUNTED = 1 << 14; michael@0: michael@0: public static final int TYPE_INTEGER_DISCRETE = FLAG_INTEGER | FLAG_DISCRETE; michael@0: public static final int TYPE_INTEGER_LAST = FLAG_INTEGER | FLAG_LAST; michael@0: public static final int TYPE_INTEGER_COUNTER = FLAG_INTEGER | FLAG_COUNTER; michael@0: michael@0: public static final int TYPE_STRING_DISCRETE = FLAG_STRING | FLAG_DISCRETE; michael@0: public static final int TYPE_STRING_LAST = FLAG_STRING | FLAG_LAST; michael@0: michael@0: public static final int TYPE_JSON_DISCRETE = FLAG_JSON | FLAG_DISCRETE; michael@0: public static final int TYPE_JSON_LAST = FLAG_JSON | FLAG_LAST; michael@0: michael@0: public static final int TYPE_COUNTED_STRING_DISCRETE = FLAG_COUNTED | TYPE_STRING_DISCRETE; michael@0: michael@0: protected int fieldID = UNKNOWN_TYPE_OR_FIELD_ID; michael@0: protected int flags; michael@0: michael@0: protected final String measurementName; michael@0: protected final String measurementVersion; michael@0: protected final String fieldName; michael@0: michael@0: public Field(String mName, int mVersion, String fieldName, int type) { michael@0: this.measurementName = mName; michael@0: this.measurementVersion = Integer.toString(mVersion, 10); michael@0: this.fieldName = fieldName; michael@0: this.flags = type; michael@0: } michael@0: michael@0: /** michael@0: * @return the ID for this Field michael@0: * @throws IllegalStateException if this field is not found in storage michael@0: */ michael@0: public abstract int getID() throws IllegalStateException; michael@0: michael@0: public boolean isIntegerField() { michael@0: return (this.flags & FLAG_INTEGER) > 0; michael@0: } michael@0: michael@0: public boolean isStringField() { michael@0: return (this.flags & FLAG_STRING) > 0; michael@0: } michael@0: michael@0: public boolean isJSONField() { michael@0: return (this.flags & FLAG_JSON) > 0; michael@0: } michael@0: michael@0: public boolean isStoredAsString() { michael@0: return (this.flags & (FLAG_JSON | FLAG_STRING)) > 0; michael@0: } michael@0: michael@0: public boolean isDiscreteField() { michael@0: return (this.flags & FLAG_DISCRETE) > 0; michael@0: } michael@0: michael@0: /** michael@0: * True if the accrued values are intended to be bucket-counted. For strings, michael@0: * each discrete value will name a bucket, with the number of instances per michael@0: * day being the value in the bucket. michael@0: */ michael@0: public boolean isCountedField() { michael@0: return (this.flags & FLAG_COUNTED) > 0; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Close open storage handles and otherwise finish up. michael@0: */ michael@0: public void close(); michael@0: michael@0: /** michael@0: * Return the day integer corresponding to the provided time. michael@0: * michael@0: * @param time michael@0: * milliseconds since Unix epoch. michael@0: * @return an integer day. michael@0: */ michael@0: public int getDay(long time); michael@0: michael@0: /** michael@0: * Return the day integer corresponding to the current time. michael@0: * michael@0: * @return an integer day. michael@0: */ michael@0: public int getDay(); michael@0: michael@0: /** michael@0: * Return a new {@link Environment}, suitable for being populated, hashed, and michael@0: * registered. michael@0: * michael@0: * @return a new {@link Environment} instance. michael@0: */ michael@0: public Environment getEnvironment(); michael@0: michael@0: /** michael@0: * @return a mapping from environment IDs to hashes, suitable for use in michael@0: * payload generation. michael@0: */ michael@0: public SparseArray getEnvironmentHashesByID(); michael@0: michael@0: /** michael@0: * @return a mapping from environment IDs to registered {@link Environment} michael@0: * records, suitable for use in payload generation. michael@0: */ michael@0: public SparseArray getEnvironmentRecordsByID(); michael@0: michael@0: /** michael@0: * @param id michael@0: * the environment ID, as returned by {@link Environment#register()}. michael@0: * @return a cursor for the record. michael@0: */ michael@0: public Cursor getEnvironmentRecordForID(int id); michael@0: michael@0: /** michael@0: * @param measurement michael@0: * the name of a measurement, such as "org.mozilla.appInfo.appInfo". michael@0: * @param measurementVersion michael@0: * the version of a measurement, such as '3'. michael@0: * @param fieldName michael@0: * the name of a field, such as "platformVersion". michael@0: * michael@0: * @return a {@link Field} instance corresponding to the provided values. michael@0: */ michael@0: public Field getField(String measurement, int measurementVersion, michael@0: String fieldName); michael@0: michael@0: /** michael@0: * @return a mapping from field IDs to {@link Field} instances, suitable for michael@0: * use in payload generation. michael@0: */ michael@0: public SparseArray getFieldsByID(); michael@0: michael@0: public void recordDailyLast(int env, int day, int field, JSONObject value); michael@0: public void recordDailyLast(int env, int day, int field, String value); michael@0: public void recordDailyLast(int env, int day, int field, int value); michael@0: public void recordDailyDiscrete(int env, int day, int field, JSONObject value); michael@0: public void recordDailyDiscrete(int env, int day, int field, String value); michael@0: public void recordDailyDiscrete(int env, int day, int field, int value); michael@0: public void incrementDailyCount(int env, int day, int field, int by); michael@0: public void incrementDailyCount(int env, int day, int field); michael@0: michael@0: /** michael@0: * Return true if events exist that were recorded on or after time. michael@0: */ michael@0: boolean hasEventSince(long time); michael@0: michael@0: /** michael@0: * Obtain a cursor over events that were recorded since time. michael@0: * This cursor exposes 'raw' events, with integer identifiers for values. michael@0: */ michael@0: public Cursor getRawEventsSince(long time); michael@0: michael@0: /** michael@0: * Obtain a cursor over events that were recorded since time. michael@0: * michael@0: * This cursor exposes 'friendly' events, with string names and full michael@0: * measurement metadata. michael@0: */ michael@0: public Cursor getEventsSince(long time); michael@0: michael@0: /** michael@0: * Ensure that a measurement and all of its fields are registered with the DB. michael@0: * No fields will be processed if the measurement exists with the specified michael@0: * version. michael@0: * michael@0: * @param measurement michael@0: * a measurement name, such as "org.mozila.appInfo.appInfo". michael@0: * @param version michael@0: * a version number, such as '3'. michael@0: * @param fields michael@0: * a {@link MeasurementFields} instance, consisting of a collection michael@0: * of field names. michael@0: */ michael@0: public void ensureMeasurementInitialized(String measurement, michael@0: int version, michael@0: MeasurementFields fields); michael@0: public Cursor getMeasurementVersions(); michael@0: public Cursor getFieldVersions(); michael@0: public Cursor getFieldVersions(String measurement, int measurementVersion); michael@0: michael@0: public void deleteEverything(); michael@0: public void deleteEnvironments(); michael@0: public void deleteMeasurements(); michael@0: /** michael@0: * Deletes all environments, addons, and events from the database before the given time. michael@0: * michael@0: * @param time milliseconds since epoch. michael@0: * @param curEnv The ID of the current environment. michael@0: * @return The number of environments and addon entries deleted. michael@0: */ michael@0: public int deleteDataBefore(final long time, final int curEnv); michael@0: michael@0: public int getEventCount(); michael@0: public int getEnvironmentCount(); michael@0: michael@0: public void pruneEvents(final int num); michael@0: public void pruneEnvironments(final int num); michael@0: michael@0: public void enqueueOperation(Runnable runnable); michael@0: }