Loading core/java/android/privacy/internal/longitudinalreporting/LongitudinalReportingEncoder.java +12 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.privacy.internal.longitudinalreporting; import android.privacy.DifferentialPrivacyEncoder; import android.privacy.internal.rappor.RapporConfig; import android.privacy.internal.rappor.RapporEncoder; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -48,6 +49,9 @@ import com.android.internal.annotations.VisibleForTesting; */ public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder { private static final String TAG = "LongitudinalEncoder"; private static final boolean DEBUG = false; // Suffix that will be added to Rappor's encoder id. There's a (relatively) small risk some // other Rappor encoder may re-use the same encoder id. private static final String PRR1_ENCODER_ID = "prr1_encoder_id"; Loading Loading @@ -121,11 +125,18 @@ public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder @Override public byte[] encodeBoolean(boolean original) { if (DEBUG) { Log.d(TAG, "encodeBoolean, encoderId:" + mConfig.getEncoderId() + ", original: " + original); } if (mFakeValue != null) { // Use the fake value generated in PRR. original = mFakeValue.booleanValue(); if (DEBUG) Log.d(TAG, "Use fake value: " + original); } return mIRREncoder.encodeBoolean(original); byte[] result = mIRREncoder.encodeBoolean(original); if (DEBUG) Log.d(TAG, "result: " + ((result[0] & 0x1) != 0)); return result; } @Override Loading services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java +16 −1 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { Slog.w(TAG, "Only shell is allowed to call network watchlist shell commands"); return; } (new NetworkWatchlistShellCommand(mContext)).exec(this, in, out, err, args, callback, (new NetworkWatchlistShellCommand(this, mContext)).exec(this, in, out, err, args, callback, resultReceiver); } Loading Loading @@ -262,6 +262,21 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { mNetworkWatchlistHandler.reportWatchlistIfNecessary(); } /** * Force generate watchlist report for testing. * * @param lastReportTime Watchlist report will cotain all records before this time. * @return True if operation success. */ public boolean forceReportWatchlistForTest(long lastReportTime) { if (mConfig.isConfigSecure()) { // Should not force generate report under production config. return false; } mNetworkWatchlistHandler.forceReportWatchlistForTest(lastReportTime); return true; } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; Loading services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java +37 −9 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.server.net.watchlist; import android.content.Context; import android.content.Intent; import android.net.NetworkWatchlistManager; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; import android.provider.Settings; import java.io.FileInputStream; import java.io.IOException; Loading @@ -34,10 +36,12 @@ import java.io.PrintWriter; */ class NetworkWatchlistShellCommand extends ShellCommand { final NetworkWatchlistManager mNetworkWatchlistManager; final Context mContext; final NetworkWatchlistService mService; NetworkWatchlistShellCommand(Context context) { mNetworkWatchlistManager = new NetworkWatchlistManager(context); NetworkWatchlistShellCommand(NetworkWatchlistService service, Context context) { mContext = context; mService = service; } @Override Loading @@ -51,11 +55,13 @@ class NetworkWatchlistShellCommand extends ShellCommand { switch(cmd) { case "set-test-config": return runSetTestConfig(); case "force-generate-report": return runForceGenerateReport(); default: return handleDefaultCommands(cmd); } } catch (RemoteException e) { pw.println("Remote exception: " + e); } catch (Exception e) { pw.println("Exception: " + e); } return -1; } Loading @@ -73,22 +79,44 @@ class NetworkWatchlistShellCommand extends ShellCommand { WatchlistConfig.getInstance().setTestMode(fileStream); } pw.println("Success!"); } catch (RuntimeException | IOException ex) { } catch (Exception ex) { pw.println("Error: " + ex.toString()); return -1; } return 0; } private int runForceGenerateReport() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final long ident = Binder.clearCallingIdentity(); try { // Reset last report time if (!WatchlistConfig.getInstance().isConfigSecure()) { pw.println("Error: Cannot force generate report under production config"); return -1; } Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L); mService.forceReportWatchlistForTest(System.currentTimeMillis()); pw.println("Success!"); } catch (Exception ex) { pw.println("Error: " + ex); return -1; } finally { Binder.restoreCallingIdentity(ident); } return 0; } @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); pw.println("Network watchlist manager commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(""); pw.println(" set-test-config your_watchlist_config.xml"); pw.println(); Intent.printIntentArgsHelp(pw , ""); pw.println(" Set network watchlist test config file."); pw.println(" force-generate-report"); pw.println(" Force generate watchlist test report."); } } services/core/java/com/android/server/net/watchlist/PrivacyUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.net.watchlist; import android.privacy.DifferentialPrivacyEncoder; import android.privacy.internal.longitudinalreporting.LongitudinalReportingConfig; import android.privacy.internal.longitudinalreporting.LongitudinalReportingEncoder; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; Loading @@ -32,6 +33,7 @@ import java.util.Map; class PrivacyUtils { private static final String TAG = "PrivacyUtils"; private static final boolean DEBUG = NetworkWatchlistService.DEBUG; /** * Parameters used for encoding watchlist reports. Loading Loading @@ -84,6 +86,7 @@ class PrivacyUtils { @VisibleForTesting static Map<String, Boolean> createDpEncodedReportMap(boolean isSecure, byte[] userSecret, List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) { if (DEBUG) Slog.i(TAG, "createDpEncodedReportMap start"); final int appDigestListSize = appDigestList.size(); final HashMap<String, Boolean> resultMap = new HashMap<>(appDigestListSize); for (int i = 0; i < appDigestListSize; i++) { Loading @@ -93,6 +96,7 @@ class PrivacyUtils { ? createSecureDPEncoder(userSecret, appDigest) : createInsecureDPEncoderForTest(appDigest); final boolean visitedWatchlist = aggregatedResult.appDigestList.contains(appDigest); if (DEBUG) Slog.i(TAG, appDigest + ": " + visitedWatchlist); // Get the least significant bit of first byte, and set result to True if it is 1 boolean encodedVisitedWatchlist = ((int) encoder.encodeBoolean(visitedWatchlist)[0] & 0x1) == 0x1; Loading services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java +75 −31 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading @@ -61,6 +62,8 @@ class WatchlistLoggingHandler extends Handler { static final int LOG_WATCHLIST_EVENT_MSG = 1; @VisibleForTesting static final int REPORT_RECORDS_IF_NECESSARY_MSG = 2; @VisibleForTesting static final int FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG = 3; private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1); private static final String DROPBOX_TAG = "network_watchlist_report"; Loading Loading @@ -110,7 +113,15 @@ class WatchlistLoggingHandler extends Handler { break; } case REPORT_RECORDS_IF_NECESSARY_MSG: tryAggregateRecords(); tryAggregateRecords(getLastMidnightTime()); break; case FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG: if (msg.obj instanceof Long) { long lastRecordTime = (Long) msg.obj; tryAggregateRecords(lastRecordTime); } else { Slog.e(TAG, "Msg.obj needs to be a Long object."); } break; default: { Slog.d(TAG, "WatchlistLoggingHandler received an unknown of message."); Loading Loading @@ -146,6 +157,12 @@ class WatchlistLoggingHandler extends Handler { sendMessage(msg); } public void forceReportWatchlistForTest(long lastReportTime) { final Message msg = obtainMessage(FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG); msg.obj = lastReportTime; sendMessage(msg); } /** * Insert network traffic event to watchlist async queue processor. */ Loading Loading @@ -177,8 +194,14 @@ class WatchlistLoggingHandler extends Handler { } private boolean insertRecord(int uid, String cncHost, long timestamp) { if (DEBUG) { Slog.i(TAG, "trying to insert record with host: " + cncHost + ", uid: " + uid); } if (!mConfig.isConfigSecure() && !isPackageTestOnly(uid)) { // Skip package if config is not secure and package is not TestOnly app. if (DEBUG) { Slog.i(TAG, "uid: " + uid + " is not test only package"); } return true; } final byte[] digest = getDigestFromUid(uid); Loading @@ -187,25 +210,25 @@ class WatchlistLoggingHandler extends Handler { return false; } final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp); tryAggregateRecords(); return result; } private boolean shouldReportNetworkWatchlist() { private boolean shouldReportNetworkWatchlist(long lastRecordTime) { final long lastReportTime = Settings.Global.getLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L); final long currentTimestamp = System.currentTimeMillis(); if (currentTimestamp < lastReportTime) { if (lastRecordTime < lastReportTime) { Slog.i(TAG, "Last report time is larger than current time, reset report"); mDbHelper.cleanup(); mDbHelper.cleanup(lastReportTime); return false; } return currentTimestamp >= lastReportTime + ONE_DAY_MS; return lastRecordTime >= lastReportTime + ONE_DAY_MS; } private void tryAggregateRecords() { private void tryAggregateRecords(long lastRecordTime) { long startTime = System.currentTimeMillis(); try { // Check if it's necessary to generate watchlist report now. if (!shouldReportNetworkWatchlist()) { if (!shouldReportNetworkWatchlist(lastRecordTime)) { Slog.i(TAG, "No need to aggregate record yet."); return; } Loading @@ -213,9 +236,9 @@ class WatchlistLoggingHandler extends Handler { if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) { Settings.Global.putLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, System.currentTimeMillis()); lastRecordTime); final WatchlistReportDbHelper.AggregatedResult aggregatedResult = mDbHelper.getAggregatedRecords(); mDbHelper.getAggregatedRecords(lastRecordTime); if (aggregatedResult == null) { Slog.i(TAG, "Cannot get result from database"); return; Loading @@ -229,8 +252,14 @@ class WatchlistLoggingHandler extends Handler { if (encodedResult != null) { addEncodedReportToDropBox(encodedResult); } } else { Slog.w(TAG, "Network Watchlist dropbox tag is not enabled"); } mDbHelper.cleanup(lastRecordTime); } finally { long endTime = System.currentTimeMillis(); Slog.i(TAG, "Milliseconds spent on tryAggregateRecords(): " + (endTime - startTime)); } mDbHelper.cleanup(); } /** Loading Loading @@ -379,4 +408,19 @@ class WatchlistLoggingHandler extends Handler { } return subDomainList.toArray(new String[0]); } static long getLastMidnightTime() { return getMidnightTimestamp(0); } static long getMidnightTimestamp(int daysBefore) { java.util.Calendar date = new GregorianCalendar(); // reset hour, minutes, seconds and millis date.set(java.util.Calendar.HOUR_OF_DAY, 0); date.set(java.util.Calendar.MINUTE, 0); date.set(java.util.Calendar.SECOND, 0); date.set(java.util.Calendar.MILLISECOND, 0); date.add(java.util.Calendar.DAY_OF_MONTH, -daysBefore); return date.getTimeInMillis(); } } Loading
core/java/android/privacy/internal/longitudinalreporting/LongitudinalReportingEncoder.java +12 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.privacy.internal.longitudinalreporting; import android.privacy.DifferentialPrivacyEncoder; import android.privacy.internal.rappor.RapporConfig; import android.privacy.internal.rappor.RapporEncoder; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -48,6 +49,9 @@ import com.android.internal.annotations.VisibleForTesting; */ public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder { private static final String TAG = "LongitudinalEncoder"; private static final boolean DEBUG = false; // Suffix that will be added to Rappor's encoder id. There's a (relatively) small risk some // other Rappor encoder may re-use the same encoder id. private static final String PRR1_ENCODER_ID = "prr1_encoder_id"; Loading Loading @@ -121,11 +125,18 @@ public class LongitudinalReportingEncoder implements DifferentialPrivacyEncoder @Override public byte[] encodeBoolean(boolean original) { if (DEBUG) { Log.d(TAG, "encodeBoolean, encoderId:" + mConfig.getEncoderId() + ", original: " + original); } if (mFakeValue != null) { // Use the fake value generated in PRR. original = mFakeValue.booleanValue(); if (DEBUG) Log.d(TAG, "Use fake value: " + original); } return mIRREncoder.encodeBoolean(original); byte[] result = mIRREncoder.encodeBoolean(original); if (DEBUG) Log.d(TAG, "result: " + ((result[0] & 0x1) != 0)); return result; } @Override Loading
services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java +16 −1 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { Slog.w(TAG, "Only shell is allowed to call network watchlist shell commands"); return; } (new NetworkWatchlistShellCommand(mContext)).exec(this, in, out, err, args, callback, (new NetworkWatchlistShellCommand(this, mContext)).exec(this, in, out, err, args, callback, resultReceiver); } Loading Loading @@ -262,6 +262,21 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { mNetworkWatchlistHandler.reportWatchlistIfNecessary(); } /** * Force generate watchlist report for testing. * * @param lastReportTime Watchlist report will cotain all records before this time. * @return True if operation success. */ public boolean forceReportWatchlistForTest(long lastReportTime) { if (mConfig.isConfigSecure()) { // Should not force generate report under production config. return false; } mNetworkWatchlistHandler.forceReportWatchlistForTest(lastReportTime); return true; } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; Loading
services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java +37 −9 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.server.net.watchlist; import android.content.Context; import android.content.Intent; import android.net.NetworkWatchlistManager; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; import android.provider.Settings; import java.io.FileInputStream; import java.io.IOException; Loading @@ -34,10 +36,12 @@ import java.io.PrintWriter; */ class NetworkWatchlistShellCommand extends ShellCommand { final NetworkWatchlistManager mNetworkWatchlistManager; final Context mContext; final NetworkWatchlistService mService; NetworkWatchlistShellCommand(Context context) { mNetworkWatchlistManager = new NetworkWatchlistManager(context); NetworkWatchlistShellCommand(NetworkWatchlistService service, Context context) { mContext = context; mService = service; } @Override Loading @@ -51,11 +55,13 @@ class NetworkWatchlistShellCommand extends ShellCommand { switch(cmd) { case "set-test-config": return runSetTestConfig(); case "force-generate-report": return runForceGenerateReport(); default: return handleDefaultCommands(cmd); } } catch (RemoteException e) { pw.println("Remote exception: " + e); } catch (Exception e) { pw.println("Exception: " + e); } return -1; } Loading @@ -73,22 +79,44 @@ class NetworkWatchlistShellCommand extends ShellCommand { WatchlistConfig.getInstance().setTestMode(fileStream); } pw.println("Success!"); } catch (RuntimeException | IOException ex) { } catch (Exception ex) { pw.println("Error: " + ex.toString()); return -1; } return 0; } private int runForceGenerateReport() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final long ident = Binder.clearCallingIdentity(); try { // Reset last report time if (!WatchlistConfig.getInstance().isConfigSecure()) { pw.println("Error: Cannot force generate report under production config"); return -1; } Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L); mService.forceReportWatchlistForTest(System.currentTimeMillis()); pw.println("Success!"); } catch (Exception ex) { pw.println("Error: " + ex); return -1; } finally { Binder.restoreCallingIdentity(ident); } return 0; } @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); pw.println("Network watchlist manager commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(""); pw.println(" set-test-config your_watchlist_config.xml"); pw.println(); Intent.printIntentArgsHelp(pw , ""); pw.println(" Set network watchlist test config file."); pw.println(" force-generate-report"); pw.println(" Force generate watchlist test report."); } }
services/core/java/com/android/server/net/watchlist/PrivacyUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.net.watchlist; import android.privacy.DifferentialPrivacyEncoder; import android.privacy.internal.longitudinalreporting.LongitudinalReportingConfig; import android.privacy.internal.longitudinalreporting.LongitudinalReportingEncoder; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; Loading @@ -32,6 +33,7 @@ import java.util.Map; class PrivacyUtils { private static final String TAG = "PrivacyUtils"; private static final boolean DEBUG = NetworkWatchlistService.DEBUG; /** * Parameters used for encoding watchlist reports. Loading Loading @@ -84,6 +86,7 @@ class PrivacyUtils { @VisibleForTesting static Map<String, Boolean> createDpEncodedReportMap(boolean isSecure, byte[] userSecret, List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) { if (DEBUG) Slog.i(TAG, "createDpEncodedReportMap start"); final int appDigestListSize = appDigestList.size(); final HashMap<String, Boolean> resultMap = new HashMap<>(appDigestListSize); for (int i = 0; i < appDigestListSize; i++) { Loading @@ -93,6 +96,7 @@ class PrivacyUtils { ? createSecureDPEncoder(userSecret, appDigest) : createInsecureDPEncoderForTest(appDigest); final boolean visitedWatchlist = aggregatedResult.appDigestList.contains(appDigest); if (DEBUG) Slog.i(TAG, appDigest + ": " + visitedWatchlist); // Get the least significant bit of first byte, and set result to True if it is 1 boolean encodedVisitedWatchlist = ((int) encoder.encodeBoolean(visitedWatchlist)[0] & 0x1) == 0x1; Loading
services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java +75 −31 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import java.io.File; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading @@ -61,6 +62,8 @@ class WatchlistLoggingHandler extends Handler { static final int LOG_WATCHLIST_EVENT_MSG = 1; @VisibleForTesting static final int REPORT_RECORDS_IF_NECESSARY_MSG = 2; @VisibleForTesting static final int FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG = 3; private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1); private static final String DROPBOX_TAG = "network_watchlist_report"; Loading Loading @@ -110,7 +113,15 @@ class WatchlistLoggingHandler extends Handler { break; } case REPORT_RECORDS_IF_NECESSARY_MSG: tryAggregateRecords(); tryAggregateRecords(getLastMidnightTime()); break; case FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG: if (msg.obj instanceof Long) { long lastRecordTime = (Long) msg.obj; tryAggregateRecords(lastRecordTime); } else { Slog.e(TAG, "Msg.obj needs to be a Long object."); } break; default: { Slog.d(TAG, "WatchlistLoggingHandler received an unknown of message."); Loading Loading @@ -146,6 +157,12 @@ class WatchlistLoggingHandler extends Handler { sendMessage(msg); } public void forceReportWatchlistForTest(long lastReportTime) { final Message msg = obtainMessage(FORCE_REPORT_RECORDS_NOW_FOR_TEST_MSG); msg.obj = lastReportTime; sendMessage(msg); } /** * Insert network traffic event to watchlist async queue processor. */ Loading Loading @@ -177,8 +194,14 @@ class WatchlistLoggingHandler extends Handler { } private boolean insertRecord(int uid, String cncHost, long timestamp) { if (DEBUG) { Slog.i(TAG, "trying to insert record with host: " + cncHost + ", uid: " + uid); } if (!mConfig.isConfigSecure() && !isPackageTestOnly(uid)) { // Skip package if config is not secure and package is not TestOnly app. if (DEBUG) { Slog.i(TAG, "uid: " + uid + " is not test only package"); } return true; } final byte[] digest = getDigestFromUid(uid); Loading @@ -187,25 +210,25 @@ class WatchlistLoggingHandler extends Handler { return false; } final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp); tryAggregateRecords(); return result; } private boolean shouldReportNetworkWatchlist() { private boolean shouldReportNetworkWatchlist(long lastRecordTime) { final long lastReportTime = Settings.Global.getLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L); final long currentTimestamp = System.currentTimeMillis(); if (currentTimestamp < lastReportTime) { if (lastRecordTime < lastReportTime) { Slog.i(TAG, "Last report time is larger than current time, reset report"); mDbHelper.cleanup(); mDbHelper.cleanup(lastReportTime); return false; } return currentTimestamp >= lastReportTime + ONE_DAY_MS; return lastRecordTime >= lastReportTime + ONE_DAY_MS; } private void tryAggregateRecords() { private void tryAggregateRecords(long lastRecordTime) { long startTime = System.currentTimeMillis(); try { // Check if it's necessary to generate watchlist report now. if (!shouldReportNetworkWatchlist()) { if (!shouldReportNetworkWatchlist(lastRecordTime)) { Slog.i(TAG, "No need to aggregate record yet."); return; } Loading @@ -213,9 +236,9 @@ class WatchlistLoggingHandler extends Handler { if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) { Settings.Global.putLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, System.currentTimeMillis()); lastRecordTime); final WatchlistReportDbHelper.AggregatedResult aggregatedResult = mDbHelper.getAggregatedRecords(); mDbHelper.getAggregatedRecords(lastRecordTime); if (aggregatedResult == null) { Slog.i(TAG, "Cannot get result from database"); return; Loading @@ -229,8 +252,14 @@ class WatchlistLoggingHandler extends Handler { if (encodedResult != null) { addEncodedReportToDropBox(encodedResult); } } else { Slog.w(TAG, "Network Watchlist dropbox tag is not enabled"); } mDbHelper.cleanup(lastRecordTime); } finally { long endTime = System.currentTimeMillis(); Slog.i(TAG, "Milliseconds spent on tryAggregateRecords(): " + (endTime - startTime)); } mDbHelper.cleanup(); } /** Loading Loading @@ -379,4 +408,19 @@ class WatchlistLoggingHandler extends Handler { } return subDomainList.toArray(new String[0]); } static long getLastMidnightTime() { return getMidnightTimestamp(0); } static long getMidnightTimestamp(int daysBefore) { java.util.Calendar date = new GregorianCalendar(); // reset hour, minutes, seconds and millis date.set(java.util.Calendar.HOUR_OF_DAY, 0); date.set(java.util.Calendar.MINUTE, 0); date.set(java.util.Calendar.SECOND, 0); date.set(java.util.Calendar.MILLISECOND, 0); date.add(java.util.Calendar.DAY_OF_MONTH, -daysBefore); return date.getTimeInMillis(); } }