1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.historyreport; 6 7 import static org.chromium.base.ThreadUtils.assertOnBackgroundThread; 8 9 import androidx.annotation.VisibleForTesting; 10 11 import org.chromium.base.Log; 12 import org.chromium.base.annotations.CalledByNative; 13 import org.chromium.base.annotations.JNINamespace; 14 import org.chromium.base.annotations.NativeMethods; 15 import org.chromium.base.task.PostTask; 16 import org.chromium.content_public.browser.UiThreadTaskTraits; 17 18 import java.io.PrintWriter; 19 import java.util.concurrent.atomic.AtomicBoolean; 20 21 /** 22 * Bridge class for calls between Java and C++. 23 */ 24 @JNINamespace("history_report") 25 public class HistoryReportJniBridge implements SearchJniBridge { 26 private static final String TAG = "historyreport"; 27 28 private long mNativeHistoryReportJniBridge; 29 private DataChangeObserver mDataChangeObserver; 30 private final AtomicBoolean mStarted = new AtomicBoolean(); 31 32 @Override init(DataChangeObserver observer)33 public boolean init(DataChangeObserver observer) { 34 // This is called in the deferred task, so we couldn't assertOnBackgroundThread(); 35 assert mDataChangeObserver == null || mDataChangeObserver == observer; 36 if (observer == null) return false; 37 if (mNativeHistoryReportJniBridge != 0) return true; 38 mDataChangeObserver = observer; 39 PostTask.runSynchronously(UiThreadTaskTraits.DEFAULT, () -> { 40 mNativeHistoryReportJniBridge = 41 HistoryReportJniBridgeJni.get().init(HistoryReportJniBridge.this); 42 }); 43 if (mNativeHistoryReportJniBridge == 0) { 44 Log.w(TAG, "JNI bridge initialization unsuccessful."); 45 return false; 46 } 47 48 Log.d(TAG, "JNI bridge initialization successful."); 49 mStarted.set(true); 50 return true; 51 } 52 isInitialized()53 private boolean isInitialized() { 54 return mNativeHistoryReportJniBridge != 0 && mDataChangeObserver != null && mStarted.get(); 55 } 56 57 @VisibleForTesting 58 @Override isStartedForTest()59 public boolean isStartedForTest() { 60 return mStarted.get(); 61 } 62 63 @Override query(long lastSeqNo, int limit)64 public DeltaFileEntry[] query(long lastSeqNo, int limit) { 65 assertOnBackgroundThread(); 66 if (!isInitialized()) { 67 Log.w(TAG, "query when JNI bridge not initialized"); 68 return new DeltaFileEntry[0]; 69 } 70 Log.d(TAG, "query %d %d", lastSeqNo, limit); 71 DeltaFileEntry[] result = HistoryReportJniBridgeJni.get().query( 72 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this, lastSeqNo, limit); 73 return result; 74 } 75 76 @Override trimDeltaFile(long seqNoLowerBound)77 public long trimDeltaFile(long seqNoLowerBound) { 78 assertOnBackgroundThread(); 79 if (!isInitialized()) { 80 Log.w(TAG, "trimDeltaFile when JNI bridge not initialized"); 81 return -1; 82 } 83 Log.d(TAG, "trimDeltaFile %d", seqNoLowerBound); 84 return HistoryReportJniBridgeJni.get().trimDeltaFile( 85 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this, seqNoLowerBound); 86 } 87 88 @Override getUsageReportsBatch(int batchSize)89 public UsageReport[] getUsageReportsBatch(int batchSize) { 90 assertOnBackgroundThread(); 91 if (!isInitialized()) { 92 Log.w(TAG, "getUsageReportsBatch when JNI bridge not initialized"); 93 return new UsageReport[0]; 94 } 95 Log.d(TAG, "getUsageReportsBatch %d", batchSize); 96 return HistoryReportJniBridgeJni.get().getUsageReportsBatch( 97 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this, batchSize); 98 } 99 100 @Override removeUsageReports(UsageReport[] reports)101 public void removeUsageReports(UsageReport[] reports) { 102 assertOnBackgroundThread(); 103 if (!isInitialized()) { 104 Log.w(TAG, "removeUsageReports when JNI bridge not initialized"); 105 return; 106 } 107 String[] reportIds = new String[reports.length]; 108 for (int i = 0; i < reports.length; ++i) { 109 reportIds[i] = reports[i].reportId; 110 } 111 HistoryReportJniBridgeJni.get().removeUsageReports( 112 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this, reportIds); 113 } 114 115 @Override clearUsageReports()116 public void clearUsageReports() { 117 assertOnBackgroundThread(); 118 if (!isInitialized()) { 119 Log.w(TAG, "clearUsageReports when JNI bridge not initialized"); 120 return; 121 } 122 HistoryReportJniBridgeJni.get().clearUsageReports( 123 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this); 124 } 125 126 @Override addHistoricVisitsToUsageReportsBuffer()127 public boolean addHistoricVisitsToUsageReportsBuffer() { 128 assertOnBackgroundThread(); 129 if (!isInitialized()) { 130 Log.w(TAG, "addHistoricVisitsToUsageReportsBuffer when JNI bridge not initialized"); 131 return false; 132 } 133 return HistoryReportJniBridgeJni.get().addHistoricVisitsToUsageReportsBuffer( 134 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this); 135 } 136 137 @Override dump(PrintWriter writer)138 public void dump(PrintWriter writer) { 139 writer.append("\nHistoryReportJniBridge [").append("started: " + mStarted.get()) 140 .append(", initialized: " + isInitialized()); 141 if (isInitialized()) { 142 writer.append(", " 143 + HistoryReportJniBridgeJni.get().dump( 144 mNativeHistoryReportJniBridge, HistoryReportJniBridge.this)); 145 } 146 writer.append("]"); 147 } 148 149 @CalledByNative createDeltaFileEntriesArray(int size)150 private static DeltaFileEntry[] createDeltaFileEntriesArray(int size) { 151 return new DeltaFileEntry[size]; 152 } 153 154 @CalledByNative setDeltaFileEntry(DeltaFileEntry[] entries, int position, long seqNo, String type, String id, String url, int score, String title, String indexedUrl)155 private static void setDeltaFileEntry(DeltaFileEntry[] entries, int position, long seqNo, 156 String type, String id, String url, int score, String title, String indexedUrl) { 157 entries[position] = new DeltaFileEntry(seqNo, type, id, url, score, title, indexedUrl); 158 } 159 160 @CalledByNative createUsageReportsArray(int size)161 private static UsageReport[] createUsageReportsArray(int size) { 162 return new UsageReport[size]; 163 } 164 165 @CalledByNative setUsageReport(UsageReport[] reports, int position, String reportId, String pageId, long timestampMs, boolean typedVisit)166 private static void setUsageReport(UsageReport[] reports, int position, String reportId, 167 String pageId, long timestampMs, boolean typedVisit) { 168 reports[position] = new UsageReport(reportId, pageId, timestampMs, typedVisit); 169 } 170 171 @CalledByNative onDataChanged()172 private void onDataChanged() { 173 Log.d(TAG, "onDataChanged"); 174 mDataChangeObserver.onDataChanged(); 175 } 176 177 @CalledByNative onDataCleared()178 private void onDataCleared() { 179 Log.d(TAG, "onDataCleared"); 180 mDataChangeObserver.onDataCleared(); 181 } 182 183 @CalledByNative startReportingTask()184 private void startReportingTask() { 185 Log.d(TAG, "startReportingTask"); 186 mDataChangeObserver.startReportingTask(); 187 } 188 189 @CalledByNative stopReportingTask()190 private void stopReportingTask() { 191 Log.d(TAG, "stopReportingTask"); 192 mDataChangeObserver.stopReportingTask(); 193 } 194 195 @NativeMethods 196 interface Natives { init(HistoryReportJniBridge caller)197 long init(HistoryReportJniBridge caller); trimDeltaFile(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, long seqNoLowerBound)198 long trimDeltaFile(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, 199 long seqNoLowerBound); query(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, long lastSeqNo, int limit)200 DeltaFileEntry[] query(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, 201 long lastSeqNo, int limit); getUsageReportsBatch( long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, int batchSize)202 UsageReport[] getUsageReportsBatch( 203 long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, int batchSize); removeUsageReports(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, String[] reportIds)204 void removeUsageReports(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller, 205 String[] reportIds); clearUsageReports(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller)206 void clearUsageReports(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller); addHistoricVisitsToUsageReportsBuffer( long nativeHistoryReportJniBridge, HistoryReportJniBridge caller)207 boolean addHistoricVisitsToUsageReportsBuffer( 208 long nativeHistoryReportJniBridge, HistoryReportJniBridge caller); dump(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller)209 String dump(long nativeHistoryReportJniBridge, HistoryReportJniBridge caller); 210 } 211 } 212