This repository has been archived by the owner on Feb 20, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Feature/#6557 Organic search telemetry #10167
Merged
boek
merged 5 commits into
mozilla-mobile:master
from
BranescuMihai:feature/#6557-organic_search_telemetry
Apr 24, 2020
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
307a6e0
For #6557 - added web-extension for cookies
BranescuMihai 71570f5
For #6557 - added metric for in_content
BranescuMihai d92a45f
For #6557 - split base extension functionality from ads
BranescuMihai 0e5999c
For #6557 - add in_content telemetry class
BranescuMihai 2fcb2c8
For #6557 - added unit tests
BranescuMihai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
const COOKIES_CHECK_TIMEOUT_MS = 1000; | ||
|
||
function sendCookies(cookies) { | ||
let message = { | ||
'url': document.location.href, | ||
'cookies': cookies | ||
} | ||
browser.runtime.sendNativeMessage("BrowserCookiesMessage", message); | ||
} | ||
|
||
function notify(message) { | ||
sendCookies(message.cookies); | ||
} | ||
|
||
browser.runtime.onMessage.addListener(notify); | ||
|
||
const events = ["pageshow", "load", "unload"]; | ||
var timeout; | ||
|
||
const eventLogger = event => { | ||
switch (event.type) { | ||
case "load": | ||
timeout = setTimeout(() => { | ||
browser.runtime.sendMessage({"checkCookies": true}); | ||
}, COOKIES_CHECK_TIMEOUT_MS); | ||
break; | ||
case "pageshow": | ||
if (event.persisted) { | ||
timeout = setTimeout(() => { | ||
browser.runtime.sendMessage({"checkCookies": true}); | ||
}, COOKIES_CHECK_TIMEOUT_MS); | ||
} | ||
break; | ||
case "unload": | ||
clearTimeout(timeout); | ||
default: | ||
console.log('Event:', event.type); | ||
} | ||
}; | ||
|
||
events.forEach(eventName => | ||
window.addEventListener(eventName, eventLogger) | ||
); |
28 changes: 28 additions & 0 deletions
28
app/src/main/assets/extensions/cookies/cookiesBackground.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
browser.runtime.onMessage.addListener(notify); | ||
|
||
function sendMessageToTabs(tabs, cookies) { | ||
for (let tab of tabs) { | ||
browser.tabs.sendMessage( | ||
tab.id, | ||
{cookies: cookies} | ||
); | ||
} | ||
} | ||
|
||
function notify(message) { | ||
if(message.checkCookies) { | ||
browser.cookies.getAll({}) | ||
.then(cookies => { | ||
browser.tabs.query({ | ||
currentWindow: true, | ||
active: true | ||
}).then(tabs => { | ||
sendMessageToTabs(tabs, cookies); | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: License? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JSONs don't allow standard comments. Looked over in AC and none of the extension manifest files have license added, so I think we have to make exceptions for these files |
||
"manifest_version": 2, | ||
"name": "Mozilla Android Components - Cookies", | ||
"version": "1.0", | ||
"content_scripts": [ | ||
{ | ||
"matches": ["https://*/*"], | ||
"include_globs": [ | ||
"https://www.google.*/search*", | ||
"https://www.baidu.com/from=844b/s*", | ||
"https://www.baidu.com/from=844b/baidu*", | ||
"https://*search.yahoo.com/search*", | ||
"https://www.bing.com/search*", | ||
"https://duckduckgo.com/*" | ||
], | ||
"js": ["cookies.js"], | ||
"run_at": "document_end" | ||
} | ||
], | ||
"background": { | ||
"scripts": ["cookiesBackground.js"] | ||
}, | ||
"permissions": [ | ||
"geckoViewAddons", | ||
"nativeMessaging", | ||
"webNavigation", | ||
"webRequest", | ||
"webRequestBlocking", | ||
"cookies", | ||
"*://*/*" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
app/src/main/java/org/mozilla/fenix/search/telemetry/BaseSearchTelemetry.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.fenix.search.telemetry | ||
|
||
import androidx.annotation.VisibleForTesting | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.collect | ||
import kotlinx.coroutines.flow.map | ||
import mozilla.components.browser.state.state.BrowserState | ||
import mozilla.components.browser.state.store.BrowserStore | ||
import mozilla.components.concept.engine.Engine | ||
import mozilla.components.concept.engine.EngineSession | ||
import mozilla.components.concept.engine.webextension.MessageHandler | ||
import mozilla.components.concept.engine.webextension.WebExtension | ||
import mozilla.components.lib.state.ext.flowScoped | ||
import mozilla.components.support.base.log.logger.Logger | ||
import mozilla.components.support.ktx.android.org.json.toList | ||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.filterChanged | ||
import org.json.JSONObject | ||
|
||
abstract class BaseSearchTelemetry { | ||
|
||
@VisibleForTesting | ||
internal val providerList = listOf( | ||
SearchProviderModel( | ||
name = "google", | ||
regexp = "^https:\\/\\/www\\.google\\.(?:.+)\\/search", | ||
queryParam = "q", | ||
codeParam = "client", | ||
codePrefixes = listOf("firefox"), | ||
followOnParams = listOf("oq", "ved", "ei"), | ||
extraAdServersRegexps = listOf("^https?:\\/\\/www\\.google(?:adservices)?\\.com\\/(?:pagead\\/)?aclk") | ||
), | ||
SearchProviderModel( | ||
name = "duckduckgo", | ||
regexp = "^https:\\/\\/duckduckgo\\.com\\/", | ||
queryParam = "q", | ||
codeParam = "t", | ||
codePrefixes = listOf("f"), | ||
extraAdServersRegexps = listOf( | ||
"^https:\\/\\/duckduckgo.com\\/y\\.js", | ||
"^https:\\/\\/www\\.amazon\\.(?:[a-z.]{2,24}).*(?:tag=duckduckgo-)" | ||
) | ||
), | ||
SearchProviderModel( | ||
name = "yahoo", | ||
regexp = "^https:\\/\\/(?:.*)search\\.yahoo\\.com\\/search", | ||
queryParam = "p" | ||
), | ||
SearchProviderModel( | ||
name = "baidu", | ||
regexp = "^https:\\/\\/www\\.baidu\\.com\\/from=844b\\/(?:s|baidu)", | ||
queryParam = "wd", | ||
codeParam = "tn", | ||
codePrefixes = listOf("34046034_", "monline_"), | ||
followOnParams = listOf("oq") | ||
), | ||
SearchProviderModel( | ||
name = "bing", | ||
regexp = "^https:\\/\\/www\\.bing\\.com\\/search", | ||
queryParam = "q", | ||
codeParam = "pc", | ||
codePrefixes = listOf("MOZ", "MZ"), | ||
followOnCookies = listOf( | ||
SearchProviderCookie( | ||
extraCodeParam = "form", | ||
extraCodePrefixes = listOf("QBRE"), | ||
host = "www.bing.com", | ||
name = "SRCHS", | ||
codeParam = "PC", | ||
codePrefixes = listOf("MOZ", "MZ") | ||
) | ||
), | ||
extraAdServersRegexps = listOf( | ||
"^https:\\/\\/www\\.bing\\.com\\/acli?c?k", | ||
"^https:\\/\\/www\\.bing\\.com\\/fd\\/ls\\/GLinkPingPost\\.aspx.*acli?c?k" | ||
) | ||
) | ||
) | ||
|
||
abstract fun install(engine: Engine, store: BrowserStore) | ||
|
||
internal fun getProviderForUrl(url: String): SearchProviderModel? { | ||
for (provider in providerList) { | ||
if (Regex(provider.regexp).containsMatchIn(url)) { | ||
return provider | ||
} | ||
} | ||
return null | ||
} | ||
|
||
internal fun installWebExtension( | ||
engine: Engine, | ||
store: BrowserStore, | ||
extensionInfo: ExtensionInfo | ||
) { | ||
engine.installWebExtension( | ||
id = extensionInfo.id, | ||
url = extensionInfo.resourceUrl, | ||
allowContentMessaging = true, | ||
onSuccess = { extension -> | ||
store.flowScoped { flow -> subscribeToUpdates(flow, extension, extensionInfo) } | ||
}, | ||
onError = { _, throwable -> | ||
Logger.error("Could not install ${extensionInfo.id} extension", throwable) | ||
}) | ||
} | ||
|
||
private suspend fun subscribeToUpdates( | ||
flow: Flow<BrowserState>, | ||
extension: WebExtension, | ||
extensionInfo: ExtensionInfo | ||
) { | ||
// Whenever we see a new EngineSession in the store then we register our content message | ||
// handler if it has not been added yet. | ||
flow.map { it.tabs } | ||
.filterChanged { it.engineState.engineSession } | ||
.collect { state -> | ||
val engineSession = state.engineState.engineSession ?: return@collect | ||
|
||
if (extension.hasContentMessageHandler(engineSession, extensionInfo.messageId)) { | ||
return@collect | ||
} | ||
extension.registerContentMessageHandler( | ||
engineSession, | ||
extensionInfo.messageId, | ||
SearchTelemetryMessageHandler() | ||
) | ||
} | ||
} | ||
|
||
protected fun <T> getMessageList(message: JSONObject, key: String): List<T> { | ||
return message.getJSONArray(key).toList() | ||
} | ||
|
||
/** | ||
* This method is used to process any valid json message coming from a web-extension | ||
*/ | ||
@VisibleForTesting | ||
internal abstract fun processMessage(message: JSONObject) | ||
|
||
@VisibleForTesting | ||
internal inner class SearchTelemetryMessageHandler : MessageHandler { | ||
|
||
override fun onMessage(message: Any, source: EngineSession?): Any? { | ||
if (message is JSONObject) { | ||
processMessage(message) | ||
} else { | ||
throw IllegalStateException("Received unexpected message: $message") | ||
} | ||
|
||
// Needs to return something that is not null and not Unit: | ||
// https://github.com/mozilla-mobile/android-components/issues/2969 | ||
return "" | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
app/src/main/java/org/mozilla/fenix/search/telemetry/ExtensionInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.fenix.search.telemetry | ||
|
||
data class ExtensionInfo( | ||
internal val id: String, | ||
internal val resourceUrl: String, | ||
internal val messageId: String | ||
) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you include the types of data that this could be, or provide an example? That way, if someone from data science is looking at our documentation, they have a very clear idea of what kind of data this looks like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this PR was merged already, I'll add a new task with the docs change