Merge "only output every kth word to log"

main
Kurt Partridge 2012-06-26 20:49:03 -07:00 committed by Android (Google) Code Review
commit 30447239e8
1 changed files with 58 additions and 8 deletions

View File

@ -197,6 +197,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Log.d(TAG, "stop called"); Log.d(TAG, "stop called");
if (mLoggingHandler != null && mLoggingState == LOGGING_STATE_ON) { if (mLoggingHandler != null && mLoggingState == LOGGING_STATE_ON) {
mLoggingState = LOGGING_STATE_STOPPING; mLoggingState = LOGGING_STATE_STOPPING;
flushEventQueue(true);
// put this in the Handler queue so pending writes are processed first. // put this in the Handler queue so pending writes are processed first.
mLoggingHandler.post(new Runnable() { mLoggingHandler.post(new Runnable() {
@Override @Override
@ -379,11 +380,52 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mCurrentLogUnit.addLogAtom(keys, values, false); mCurrentLogUnit.addLogAtom(keys, values, false);
} }
// Used to track how often words are logged. Too-frequent logging can leak
// semantics, disclosing private data.
/* package for test */ static class LoggingFrequencyState {
private static final int DEFAULT_WORD_LOG_FREQUENCY = 10;
private int mWordsRemainingToSkip;
private final int mFrequency;
/**
* Tracks how often words may be uploaded.
*
* @param frequency 1=Every word, 2=Every other word, etc.
*/
public LoggingFrequencyState(int frequency) {
mFrequency = frequency;
mWordsRemainingToSkip = mFrequency;
}
public void onWordLogged() {
mWordsRemainingToSkip = mFrequency;
}
public void onWordNotLogged() {
if (mWordsRemainingToSkip > 1) {
mWordsRemainingToSkip--;
}
}
public boolean isSafeToLog() {
return mWordsRemainingToSkip <= 1;
}
}
/* package for test */ LoggingFrequencyState mLoggingFrequencyState =
new LoggingFrequencyState(LoggingFrequencyState.DEFAULT_WORD_LOG_FREQUENCY);
/* package for test */ boolean isPrivacyThreat(String word) { /* package for test */ boolean isPrivacyThreat(String word) {
// currently: word not in dictionary or contains numbers. // Current checks:
// - Word not in dictionary
// - Word contains numbers
// - Privacy-safe word not logged recently
if (TextUtils.isEmpty(word)) { if (TextUtils.isEmpty(word)) {
return false; return false;
} }
if (!mLoggingFrequencyState.isSafeToLog()) {
return true;
}
final int length = word.length(); final int length = word.length();
boolean hasLetter = false; boolean hasLetter = false;
for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
@ -410,15 +452,26 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return false; return false;
} }
private void onWordComplete(String word) {
final boolean isPrivacyThreat = isPrivacyThreat(word);
flushEventQueue(isPrivacyThreat);
if (isPrivacyThreat) {
mLoggingFrequencyState.onWordNotLogged();
} else {
mLoggingFrequencyState.onWordLogged();
}
}
/** /**
* Write out enqueued LogEvents to the log, possibly dropping privacy sensitive events. * Write out enqueued LogEvents to the log, possibly dropping privacy sensitive events.
*/ */
/* package for test */ synchronized void flushQueue(boolean removePotentiallyPrivateEvents) { /* package for test */ synchronized void flushEventQueue(
boolean removePotentiallyPrivateEvents) {
if (isAllowedToLog()) { if (isAllowedToLog()) {
mCurrentLogUnit.setRemovePotentiallyPrivateEvents(removePotentiallyPrivateEvents); mCurrentLogUnit.setRemovePotentiallyPrivateEvents(removePotentiallyPrivateEvents);
mLoggingHandler.post(mCurrentLogUnit); mLoggingHandler.post(mCurrentLogUnit);
mCurrentLogUnit = new LogUnit();
} }
mCurrentLogUnit = new LogUnit();
} }
private synchronized void outputEvent(final String[] keys, final Object[] values) { private synchronized void outputEvent(final String[] keys, final Object[] values) {
@ -652,7 +705,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent( researchLogger.enqueuePotentiallyPrivateEvent(
EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values); EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values);
researchLogger.flushQueue(researchLogger.isPrivacyThreat(autoCorrection));
} }
private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = { private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = {
@ -665,7 +717,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}; };
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values); researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values);
researchLogger.flushQueue(researchLogger.isPrivacyThreat(scrubbedWord)); researchLogger.onWordComplete(scrubbedWord);
} }
private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = { private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = {
@ -743,7 +795,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
} }
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values); researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
researchLogger.flushQueue(true); // Play it safe. Remove privacy-sensitive events. researchLogger.flushEventQueue(true); // Play it safe. Remove privacy-sensitive events.
} }
} }
@ -824,7 +876,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent( researchLogger.enqueuePotentiallyPrivateEvent(
EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values); EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values);
researchLogger.flushQueue(researchLogger.isPrivacyThreat(cs.toString()));
} }
private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = { private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = {
@ -839,7 +890,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY, researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY,
values); values);
researchLogger.flushQueue(researchLogger.isPrivacyThreat(suggestion.toString()));
} }
private static final String[] EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION = { private static final String[] EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION = {