| Index: chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java | 
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java | 
| index f56846a9e1520392f10e63580250c007eebfb28f..21ddc0271eb768575e7c39105088fe9066cbd655 100644 | 
| --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java | 
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java | 
| @@ -6,25 +6,135 @@ package org.chromium.chrome.browser.contextualsearch; | 
|  | 
| import org.chromium.base.Log; | 
|  | 
| +import java.net.URL; | 
| + | 
| /** | 
| * Implements the UMA logging for Ranker that's used for Contextual Search Tap Suppression. | 
| */ | 
| public class ContextualSearchRankerLoggerImpl implements ContextualSearchRankerLogger { | 
| private static final String TAG = "ContextualSearch"; | 
|  | 
| +    // Pointer to the native instance of this class. | 
| +    private long mNativePointer; | 
| + | 
| +    // Whether logging for the current URL is currently setup. | 
| +    private boolean mIsLoggingSetup; | 
| + | 
| +    // Whether the service is ready to actually record log data. | 
| +    private boolean mCanServiceActuallyRecord; | 
| + | 
| +    // Whether any data has been written to the log since calling setupLoggingForPage(). | 
| +    private boolean mDidLog; | 
| + | 
| +    /** | 
| +     * Constructs a Ranker Logger and associated native implementation to write Contextual Search | 
| +     * ML data to Ranker. | 
| +     */ | 
| +    public ContextualSearchRankerLoggerImpl() { | 
| +        if (isEnabled()) mNativePointer = nativeInit(); | 
| +    } | 
| + | 
| +    /** | 
| +     * This method should be called to clean up storage when an instance of this class is | 
| +     * no longer in use.  The nativeDestroy will call the destructor on the native instance. | 
| +     */ | 
| +    void destroy() { | 
| +        if (isEnabled()) { | 
| +            assert mNativePointer != 0; | 
| +            writeLogAndReset(); | 
| +            nativeDestroy(mNativePointer); | 
| +            mNativePointer = 0; | 
| +            mCanServiceActuallyRecord = false; | 
| +            mDidLog = false; | 
| +        } | 
| +        mIsLoggingSetup = false; | 
| +    } | 
| + | 
| +    @Override | 
| +    public void setupLoggingForPage(URL basePageUrl) { | 
| +        mIsLoggingSetup = true; | 
| +        if (isEnabled()) { | 
| +            // The URL may be null for custom Chrome URIs like chrome://flags. | 
| +            if (basePageUrl != null) { | 
| +                nativeSetupLoggingAndRanker(mNativePointer, basePageUrl.toString()); | 
| +                mCanServiceActuallyRecord = true; | 
| +            } | 
| +        } | 
| +    } | 
| + | 
| @Override | 
| public void log(Feature feature, Object value) { | 
| -        // TODO(donnd): log to an actual persistent proto ASAP! | 
| -        Log.v(TAG, "log %s with value %s", feature.toString(), value); | 
| +        assert mIsLoggingSetup; | 
| +        if (!isEnabled()) return; | 
| + | 
| +        // TODO(donnd): Add some enforcement that log() calls are done before inference time. | 
| +        logInternal(feature, value); | 
| } | 
|  | 
| @Override | 
| -    public void logOutcome(Object value) { | 
| -        log(Feature.OUTCOME_WAS_PANEL_OPENED, value); | 
| +    public void logOutcome(Feature feature, Object value) { | 
| +        assert mIsLoggingSetup; | 
| +        if (!isEnabled()) return; | 
| + | 
| +        logInternal(feature, value); | 
| } | 
|  | 
| @Override | 
| public void writeLogAndReset() { | 
| -        Log.v(TAG, "Reset!\n"); | 
| +        if (isEnabled()) { | 
| +            if (mDidLog) nativeWriteLogAndReset(mNativePointer); | 
| +            mCanServiceActuallyRecord = false; | 
| +            mDidLog = false; | 
| +        } | 
| +        mIsLoggingSetup = false; | 
| +    } | 
| + | 
| +    /** Whether actually writing data is enabled.  If not, we may do nothing or print. */ | 
| +    private boolean isEnabled() { | 
| +        return ContextualSearchFieldTrial.isRankerLoggingEnabled(); | 
| } | 
| + | 
| +    /** | 
| +     * Logs the given feature/value after checking that logging has been set up. | 
| +     * @param feature The feature to log. | 
| +     * @param value The value to log. | 
| +     */ | 
| +    private void logInternal(Feature feature, Object value) { | 
| +        if (value instanceof Boolean) { | 
| +            logToNative(feature.toString(), ((boolean) value ? 1 : 0)); | 
| +        } else if (value instanceof Integer) { | 
| +            logToNative(feature.toString(), Long.valueOf((int) value)); | 
| +        } else if (value instanceof Long) { | 
| +            logToNative(feature.toString(), (long) value); | 
| +        } else if (value instanceof Character) { | 
| +            logToNative(feature.toString(), Character.getNumericValue((char) value)); | 
| +        } else { | 
| +            Log.w(TAG, | 
| +                    "Could not log feature to Ranker: " + feature.toString() + " of class " | 
| +                            + value.getClass()); | 
| +        } | 
| +    } | 
| + | 
| +    /** | 
| +     * Logs to the native instance.  All native logging must go through this bottleneck. | 
| +     * @param feature The feature to log. | 
| +     * @param value The value to log. | 
| +     */ | 
| +    private void logToNative(String feature, long value) { | 
| +        if (mCanServiceActuallyRecord) { | 
| +            nativeLogLong(mNativePointer, feature, value); | 
| +            mDidLog = true; | 
| +        } | 
| +    } | 
| + | 
| +    // ============================================================================================ | 
| +    // Native methods. | 
| +    // ============================================================================================ | 
| +    private native long nativeInit(); | 
| +    private native void nativeDestroy(long nativeContextualSearchRankerLoggerImpl); | 
| +    private native void nativeLogLong( | 
| +            long nativeContextualSearchRankerLoggerImpl, String featureString, long value); | 
| +    private native void nativeSetupLoggingAndRanker( | 
| +            long nativeContextualSearchRankerLoggerImpl, String basePageUrl); | 
| +    private native void nativeWriteLogAndReset(long nativeContextualSearchRankerLoggerImpl); | 
| } | 
|  |