summaryrefslogtreecommitdiff
path: root/bordeaux/service
diff options
context:
space:
mode:
authorRuei-sung Lin <rslin@google.com>2012-09-19 18:12:24 -0700
committerRuei-sung Lin <rslin@google.com>2012-10-10 16:01:36 -0700
commit47c0dc05cde9e9d9cc57e1393429006bf8b23b32 (patch)
tree2b34455aad8103d39086bbd5f83b6e280645060a /bordeaux/service
parent1253e9fb0b5570ab8adaed222655a5b052aa072e (diff)
downloadml-47c0dc05cde9e9d9cc57e1393429006bf8b23b32.tar.gz
1. avoid battery drain in location aggregator
2. add thresholding in histogram predictor 3. add paired (loction and time) features Change-Id: I2f9e59cc1da454c6dc77dd7395e2082195993ac2
Diffstat (limited to 'bordeaux/service')
-rw-r--r--bordeaux/service/src/android/bordeaux/services/AggregatorManager.java3
-rw-r--r--bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java4
-rw-r--r--bordeaux/service/src/android/bordeaux/services/BordeauxService.java2
-rw-r--r--bordeaux/service/src/android/bordeaux/services/ClusterManager.java10
-rw-r--r--bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java46
-rw-r--r--bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java142
-rw-r--r--bordeaux/service/src/android/bordeaux/services/Predictor.java47
7 files changed, 182 insertions, 72 deletions
diff --git a/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java b/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java
index 87b79258c..0fea228a7 100644
--- a/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java
+++ b/bordeaux/service/src/android/bordeaux/services/AggregatorManager.java
@@ -60,7 +60,7 @@ class AggregatorManager extends IAggregatorManager.Stub {
public void registerAggregator(Aggregator agg, AggregatorManager m) {
if (mAggregators.get(agg.getClass().getName()) != null) {
// only one instance
- throw new RuntimeException("Can't register more than one instance");
+ // throw new RuntimeException("Can't register more than one instance");
}
mAggregators.put(agg.getClass().getName(), agg);
agg.setManager(m);
@@ -68,6 +68,7 @@ class AggregatorManager extends IAggregatorManager.Stub {
for ( int i = 0; i< fl.length; i ++)
sFeatureMap.put(fl[i], agg);
}
+
// Start of IAggregatorManager interface
public ArrayList<StringString> getData(String dataName) {
return getList(getDataMap(dataName));
diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java b/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java
index 4e0223fa7..ac46af11f 100644
--- a/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java
+++ b/bordeaux/service/src/android/bordeaux/services/BordeauxPredictor.java
@@ -50,7 +50,7 @@ public class BordeauxPredictor {
public boolean reset() {
if (!retrievePredictor()){
- Log.e(TAG, PREDICTOR_NOTAVAILABLE);
+ Log.e(TAG, "reset: " + PREDICTOR_NOTAVAILABLE);
return false;
}
try {
@@ -66,7 +66,7 @@ public class BordeauxPredictor {
mPredictor = BordeauxManagerService.getPredictor(mContext, mName);
}
if (mPredictor == null) {
- Log.e(TAG, PREDICTOR_NOTAVAILABLE);
+ Log.e(TAG, "retrievePredictor: " + PREDICTOR_NOTAVAILABLE);
return false;
}
return true;
diff --git a/bordeaux/service/src/android/bordeaux/services/BordeauxService.java b/bordeaux/service/src/android/bordeaux/services/BordeauxService.java
index 41ee11026..48d41d942 100644
--- a/bordeaux/service/src/android/bordeaux/services/BordeauxService.java
+++ b/bordeaux/service/src/android/bordeaux/services/BordeauxService.java
@@ -103,6 +103,8 @@ public class BordeauxService extends Service {
// Unregister all callbacks.
mCallbacks.kill();
+ mLocationStatsAggregator.release();
+
Log.i(TAG, "Bordeaux service stopped.");
}
diff --git a/bordeaux/service/src/android/bordeaux/services/ClusterManager.java b/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
index 249be860b..4f0dd6806 100644
--- a/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
+++ b/bordeaux/service/src/android/bordeaux/services/ClusterManager.java
@@ -50,8 +50,8 @@ public class ClusterManager {
// stayed for at least 10 minutes (600 seconds) within a day.
private static final long SEMANTIC_CLUSTER_THRESHOLD = 600; // seconds
- // Reset location cluters every 12 hours (43200 seconds).
- private static final long LOCATION_REFRESH_PERIOD = 43200; // seconds
+ // Reset location cluters every 24 hours (86400 seconds).
+ private static final long LOCATION_REFRESH_PERIOD = 86400; // seconds
private static String UNKNOWN_LOCATION = "Unknown Location";
@@ -111,6 +111,9 @@ public class ClusterManager {
long currentTime = location.getTime() / 1000; // measure time in seconds
if (mLastLocation != null) {
+ if (location.getTime() == mLastLocation.getTime()) {
+ return;
+ }
// get the duration spent in the last location
long duration = (location.getTime() - mLastLocation.getTime()) / 1000;
mClusterDuration += duration;
@@ -204,7 +207,8 @@ public class ClusterManager {
String bestClusterId = "Unused Id";
for (BaseCluster cluster : mSemanticClusters) {
float distance = cluster.distanceToCluster(candidate);
- Log.v(TAG, distance + "distance to semantic cluster: " + cluster.getSemanticId());
+ Log.v(TAG, distance + "distance to semantic cluster: " +
+ cluster.getSemanticId());
if (distance < bestClusterDistance) {
bestClusterDistance = distance;
diff --git a/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java b/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java
index 3566950d2..75a4a9f28 100644
--- a/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java
+++ b/bordeaux/service/src/android/bordeaux/services/FeatureAssembly.java
@@ -18,6 +18,8 @@ package android.bordeaux.services;
import android.os.IBinder;
import android.util.Log;
+import android.util.Pair;
+import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
@@ -25,29 +27,41 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
-import android.bordeaux.services.AggregatorManager;
-import android.bordeaux.services.Aggregator;
-import java.io.Serializable;
class FeatureAssembly {
private static final String TAG = "FeatureAssembly";
private List<String> mPossibleFeatures;
private HashSet<String> mUseFeatures;
+ private HashSet<Pair<String, String> > mUsePairedFeatures;
private AggregatorManager mAggregatorManager;
public FeatureAssembly() {
mAggregatorManager = AggregatorManager.getInstance();
mPossibleFeatures = Arrays.asList(mAggregatorManager.getListOfFeatures());
mUseFeatures = new HashSet<String>();
+ mUsePairedFeatures = new HashSet<Pair<String, String> >();
}
public boolean registerFeature(String s) {
- boolean res = mPossibleFeatures.contains(s);
- if (res){
- if (!mUseFeatures.contains(s))
- mUseFeatures.add(s);
+ if (mPossibleFeatures.contains(s)) {
+ mUseFeatures.add(s);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean registerFeaturePair(String[] features) {
+ if (features.length != 2 ||
+ !mPossibleFeatures.contains(features[0]) ||
+ !mPossibleFeatures.contains(features[1])) {
+ return false;
+ } else {
+ mUseFeatures.add(features[0]);
+ mUseFeatures.add(features[1]);
+ mUsePairedFeatures.add(Pair.create(features[0], features[1]));
+ return true;
}
- return res;
}
public Set<String> getUsedFeatures() {
@@ -66,12 +80,26 @@ class FeatureAssembly {
if (features.size() > 1) {
throw new RuntimeException("Incorrect feature format extracted from aggregator.");
}
-
featureMap.putAll(features);
}
+
+ if (!mUsePairedFeatures.isEmpty()) {
+ itr = mUsePairedFeatures.iterator();
+ while(itr.hasNext()) {
+ Pair<String, String> pair = (Pair<String, String>) itr.next();
+ if (featureMap.containsKey(pair.first) &&
+ featureMap.containsKey(pair.second)) {
+ String key = pair.first + Predictor.FEATURE_SEPARATOR + pair.second;
+ String value = featureMap.get(pair.first) + Predictor.FEATURE_SEPARATOR +
+ featureMap.get(pair.second);
+ featureMap.put(key, value);
+ }
+ }
+ }
return (Map)featureMap;
}
+
public String augmentFeatureInputString(String s) {
String fs = s;
Iterator itr = mUseFeatures.iterator();
diff --git a/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
index 0390b7fbf..6f792be77 100644
--- a/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
+++ b/bordeaux/service/src/android/bordeaux/services/LocationStatsAggregator.java
@@ -16,7 +16,12 @@
package android.bordeaux.services;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
@@ -27,6 +32,8 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
+import android.os.SystemClock;
+import android.text.format.Time;
import android.util.Log;
import java.util.HashMap;
import java.util.List;
@@ -40,13 +47,9 @@ public class LocationStatsAggregator extends Aggregator {
public static final String CURRENT_SPEED = "Current Speed";
public static final String UNKNOWN_LOCATION = "Unknown Location";
- // TODO: Collect location on every minute (60000 milliseconds)
- private static final long MINIMUM_TIME = 60000;
+ private static final long REPEAT_INTERVAL = 120000;
- // reset best location provider on every 10 minutes (300000 milliseconds)
- private static final int BEST_PROVIDER_DURATION = 600000;
-
- private static final float MINIMUM_DISTANCE = 0f; // meter
+ private static final long FRESH_THRESHOLD = 90000;
private static final int LOCATION_CHANGE = 1;
@@ -55,17 +58,57 @@ public class LocationStatsAggregator extends Aggregator {
private Handler mHandler;
private HandlerThread mHandlerThread;
+ private AlarmManager mAlarmManager;
private LocationManager mLocationManager;
+
private ClusterManager mClusterManager;
+ private Criteria mCriteria = new Criteria();
+
+ private LocationUpdater mLocationUpdater;
+
+ private Context mContext;
+ private PendingIntent mPendingIntent;
+
// Fake location, used for testing.
private String mFakeLocation = null;
public LocationStatsAggregator(final Context context) {
mLocationManager =
(LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ mAlarmManager =
+ (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
setClusteringThread(context);
- requestLocationUpdate();
+
+ mCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
+ mCriteria.setPowerRequirement(Criteria.POWER_LOW);
+ /*
+ mCriteria.setAltitudeRequired(false);
+ mCriteria.setBearingRequired(false);
+ mCriteria.setSpeedRequired(true);
+ */
+ mCriteria.setCostAllowed(true);
+
+
+ IntentFilter filter = new IntentFilter(LocationUpdater.LOCATION_UPDATE);
+ mLocationUpdater = new LocationUpdater();
+ context.registerReceiver(mLocationUpdater, filter);
+
+ Intent intent = new Intent(LocationUpdater.LOCATION_UPDATE);
+
+ mContext = context;
+ mPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+
+ mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + 30000, //
+ REPEAT_INTERVAL,
+ mPendingIntent);
+ }
+
+ public void release() {
+ mContext.unregisterReceiver(mLocationUpdater);
+ mAlarmManager.cancel(mPendingIntent);
}
public String[] getListOfFeatures(){
@@ -106,6 +149,54 @@ public class LocationStatsAggregator extends Aggregator {
else mFakeLocation = null;
}
+ private Location getLastKnownLocation() {
+ List<String> providers = mLocationManager.getAllProviders();
+ Location bestResult = null;
+ float bestAccuracy = Float.MAX_VALUE;
+ long bestTime;
+
+ // get the latest location data
+ long currTime = System.currentTimeMillis();
+ for (String provider : providers) {
+ Location location = mLocationManager.getLastKnownLocation(provider);
+
+ if (location != null) {
+ float accuracy = location.getAccuracy();
+ long time = location.getTime();
+
+ if (currTime - time < FRESH_THRESHOLD && accuracy < bestAccuracy) {
+ bestResult = location;
+ bestAccuracy = accuracy;
+ bestTime = time;
+ }
+ }
+ }
+ if (bestResult != null) {
+ Log.i(TAG, "found location for free: " + bestResult);
+ }
+ return bestResult;
+ }
+
+ private class LocationUpdater extends BroadcastReceiver {
+ String TAG = "LocationUpdater";
+
+ public static final String LOCATION_UPDATE = "android.bordeaux.services.LOCATION_UPDATE";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Location location = getLastKnownLocation();
+
+ if (location == null) {
+ String provider = mLocationManager.getBestProvider(mCriteria, true);
+ Log.i(TAG, "Best Available Location Provider: " + provider);
+ mLocationManager.requestSingleUpdate(provider, mLocationListener,
+ mHandlerThread.getLooper());
+ } else {
+ mHandler.sendMessage(mHandler.obtainMessage(LOCATION_CHANGE, location));
+ }
+ }
+ }
+
private void setClusteringThread(Context context) {
mClusterManager = new ClusterManager(context);
@@ -131,43 +222,12 @@ public class LocationStatsAggregator extends Aggregator {
};
}
- private void requestLocationUpdate() {
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_COARSE);
- criteria.setPowerRequirement(Criteria.POWER_LOW);
- /*
- criteria.setAltitudeRequired(false);
- criteria.setBearingRequired(false);
- criteria.setSpeedRequired(true);
- */
- criteria.setCostAllowed(true);
-
- String bestProvider = mLocationManager.getBestProvider(criteria, false);
- Log.i(TAG, "Best Location Provider: " + bestProvider);
-
- String bestAvailableProvider = mLocationManager.getBestProvider(criteria, true);
- Log.i(TAG, "Best Available Location Provider: " + bestAvailableProvider);
-
- mProviderSetTime = System.currentTimeMillis();
- if (bestAvailableProvider != null) {
- mLocationManager.requestLocationUpdates(
- bestAvailableProvider, MINIMUM_TIME, MINIMUM_DISTANCE, mLocationListener);
- }
- }
-
private final LocationListener mLocationListener = new LocationListener() {
+ private static final String TAG = "LocationListener";
+
public void onLocationChanged(Location location) {
- long currentTime = location.getTime();
- if (currentTime - mProviderSetTime < MINIMUM_TIME) {
- return;
- }
mHandler.sendMessage(mHandler.obtainMessage(LOCATION_CHANGE, location));
- // search again for the location service
- if (currentTime - mProviderSetTime > BEST_PROVIDER_DURATION) {
- mLocationManager.removeUpdates(this);
- Log.e(TAG, "reselect best location provider");
- requestLocationUpdate();
- }
+ mLocationManager.removeUpdates(this);
}
public void onStatusChanged(String provider, int status, Bundle extras) { }
diff --git a/bordeaux/service/src/android/bordeaux/services/Predictor.java b/bordeaux/service/src/android/bordeaux/services/Predictor.java
index e2bad2e8b..b3c0d4554 100644
--- a/bordeaux/service/src/android/bordeaux/services/Predictor.java
+++ b/bordeaux/service/src/android/bordeaux/services/Predictor.java
@@ -39,19 +39,35 @@ public class Predictor extends IPredictor.Stub
private final String TAG = "Predictor";
private ModelChangeCallback modelChangeCallback = null;
- private HistogramPredictor mPredictor = new HistogramPredictor();
private FeatureAssembly mFeatureAssembly = new FeatureAssembly();
- public static final String SET_FEATURE = "Set Feature";
- public static final String USE_HISTORY = "Use History";
-
- public static final String PREVIOUS_SAMPLE = "Previous Sample";
+ public static final String SET_FEATURE = "SetFeature";
+ public static final String SET_PAIRED_FEATURES = "SetPairedFeatures";
+ public static final String FEATURE_SEPARATOR = ":";
+ public static final String USE_HISTORY = "UseHistory";
+ public static final String PREVIOUS_SAMPLE = "PreviousSample";
private boolean mUseHistory = false;
private long mHistorySpan = 0;
private String mPrevSample;
private long mPrevSampleTime;
+ // TODO: blacklist should be set outside Bordeaux service!
+ private static final String[] APP_BLACKLIST = {
+ "com.android.contacts",
+ "com.android.chrome",
+ "com.android.providers.downloads.ui",
+ "com.android.settings",
+ "com.android.vending",
+ "com.android.mms",
+ "com.google.android.gm",
+ "com.google.android.gallery3d",
+ "com.google.android.apps.googlevoice",
+ };
+
+ private HistogramPredictor mPredictor = new HistogramPredictor(APP_BLACKLIST);
+
+
/**
* Reset the Predictor
*/
@@ -70,7 +86,7 @@ public class Predictor extends IPredictor.Stub
*/
public void pushNewSample(String sampleName) {
Map<String, String> sampleFeatures = getSampleFeatures();
- Log.e(TAG, "pushNewSample " + sampleName + ": " + sampleFeatures);
+ Log.i(TAG, "pushNewSample " + sampleName + ": " + sampleFeatures);
// TODO: move to the end of the function?
mPrevSample = sampleName;
@@ -99,16 +115,11 @@ public class Predictor extends IPredictor.Stub
* return probabilty of an exmple using the histogram
*/
public List<StringFloat> getTopCandidates(int topK) {
- ArrayList<StringFloat> result = new ArrayList<StringFloat>(topK);
Map<String, String> features = getSampleFeatures();
-
List<Map.Entry<String, Double> > topApps = mPredictor.findTopClasses(features, topK);
int listSize = topApps.size();
- if (topK > 0) {
- listSize = Math.min(topK, listSize);
- }
-
+ ArrayList<StringFloat> result = new ArrayList<StringFloat>(listSize);
for (int i = 0; i < listSize; ++i) {
Map.Entry<String, Double> entry = topApps.get(i);
result.add(new StringFloat(entry.getKey(), entry.getValue().floatValue()));
@@ -121,18 +132,22 @@ public class Predictor extends IPredictor.Stub
* and 2) featureAssembly e.g. time and location.
*/
public boolean setPredictorParameter(String key, String value) {
+ Log.i(TAG, "setParameter : " + key + ", " + value);
boolean result = true;
if (key.equals(SET_FEATURE)) {
result = mFeatureAssembly.registerFeature(value);
- if (result) {
- mPredictor.useFeature(value);
- } else {
+ if (!result) {
Log.e(TAG,"Setting on feauture: " + value + " which is not available");
}
+ } else if (key.equals(SET_PAIRED_FEATURES)) {
+ String[] features = value.split(FEATURE_SEPARATOR);
+ result = mFeatureAssembly.registerFeaturePair(features);
+ if (!result) {
+ Log.e(TAG,"Setting feauture pair: " + value + " is not valid");
+ }
} else if (key.equals(USE_HISTORY)) {
mUseHistory = true;
mHistorySpan = Long.valueOf(value);
- mPredictor.useFeature(PREVIOUS_SAMPLE);
} else {
Log.e(TAG,"Setting parameter " + key + " with " + value + " is not valid");
}