Skip to content

Update Analytics to use new options struct. #1745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions analytics/generate_windows_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o
f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n")
f.write(f"#ifndef {header_guard}\n")
f.write(f"#define {header_guard}\n\n")
f.write(f"#define ANALYTICS_API // filter out from header copy\n\n")
f.write("#include <stdbool.h> // needed for bool type in pure C\n\n")

f.write("// --- Copied from original header ---\n")
Expand Down
61 changes: 50 additions & 11 deletions analytics/src/analytics_desktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@

#if defined(_WIN32)
#include <windows.h>

#include "analytics/src/analytics_windows.h"
#include "analytics_windows.h"
#endif // defined(_WIN32)

namespace firebase {
Expand All @@ -39,6 +38,13 @@ namespace analytics {
#define ANALYTICS_DLL_FILENAME L"analytics_win.dll"

static HMODULE g_analytics_module = 0;
// It's generally safer to use local std::string copies within Initialize
// for app_id and package_name to ensure their lifetime if Initialize
// could theoretically be called multiple times with different App objects,
// or if AppOptions getters returned temporaries.
// Given AppOptions structure, direct use of app.options().app_id() etc.
// within the Initialize call *should* be safe as App outlives the call,
// but local copies are more robust.
#endif // defined(_WIN32)

// Future data for analytics.
Expand All @@ -49,10 +55,7 @@ static int g_fake_instance_id = 0;
// Initializes the Analytics desktop API.
// This function must be called before any other Analytics methods.
void Initialize(const App& app) {
// The 'app' parameter is not directly used by the underlying Google Analytics
// C API for Windows for global initialization. It's included for API
// consistency with other Firebase platforms.
(void)app;
// app parameter is now used to retrieve AppOptions.

g_initialized = true;
internal::RegisterTerminateOnDefaultAppDestroy();
Expand All @@ -62,17 +65,18 @@ void Initialize(const App& app) {
#if defined(_WIN32)
if (!g_analytics_module) {
std::vector<std::string> allowed_hashes;
for (int i=0; i < FirebaseAnalytics_KnownWindowsDllHashCount; i++) {
allowed_hashes.push_back(std::string(FirebaseAnalytics_KnownWindowsDllHashes[i]));
for (int i = 0; i < FirebaseAnalytics_KnownWindowsDllHashCount; i++) {
allowed_hashes.push_back(
std::string(FirebaseAnalytics_KnownWindowsDllHashes[i]));
}

g_analytics_module =
firebase::analytics::internal::VerifyAndLoadAnalyticsLibrary(
ANALYTICS_DLL_FILENAME, allowed_hashes);

if (g_analytics_module) {
int num_loaded = FirebaseAnalytics_LoadDynamicFunctions(
g_analytics_module); // Ensure g_analytics_module is used
int num_loaded =
FirebaseAnalytics_LoadDynamicFunctions(g_analytics_module);
if (num_loaded < FirebaseAnalytics_DynamicFunctionCount) {
LogWarning(
"Analytics: Failed to load functions from Google Analytics "
Expand All @@ -81,12 +85,47 @@ void Initialize(const App& app) {
FirebaseAnalytics_UnloadDynamicFunctions();
FreeLibrary(g_analytics_module);
g_analytics_module = 0;
// Do not proceed with C API initialization if functions didn't load
} else {
LogInfo("Analytics: Loaded Google Analytics module.");

// Initialize Google Analytics C API
std::string current_app_id = app.options().app_id();
std::string current_package_name = app.options().package_name();

GoogleAnalytics_Options* c_options = GoogleAnalytics_Options_Create();
if (!c_options) {
LogError("Analytics: Failed to create GoogleAnalytics_Options.");
} else {
c_options->app_id = current_app_id.c_str();
c_options->package_name = current_package_name.c_str();
c_options->analytics_collection_enabled_at_first_launch = true;
// c_options->reserved is initialized by
// GoogleAnalytics_Options_Create

LogInfo(
"Analytics: Initializing Google Analytics C API with App ID: %s, "
"Package Name: %s",
c_options->app_id ? c_options->app_id : "null",
c_options->package_name ? c_options->package_name : "null");

if (!GoogleAnalytics_Initialize(c_options)) {
LogError("Analytics: Failed to initialize Google Analytics C API.");
// GoogleAnalytics_Initialize destroys c_options automatically if
// created by _Create
} else {
LogInfo(
"Analytics: Google Analytics C API initialized successfully.");
}
}
}
} else {
// LogWarning for g_analytics_module load failure is handled by
// VerifyAndLoadAnalyticsLibrary
g_analytics_module = 0; // Ensure it's null if loading failed
}
}
#endif
#endif // defined(_WIN32)
}

namespace internal {
Expand Down
2 changes: 2 additions & 0 deletions analytics/src/analytics_desktop_dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_
#define FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_

#define ANALYTICS_API // filter out from header copy

#include <stdbool.h> // needed for bool type in pure C

// --- Copied from original header ---
Expand Down
28 changes: 16 additions & 12 deletions analytics/src/analytics_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ static std::string CalculateFileSha256(HANDLE hFile) {
DWORD dwError = GetLastError();
LogError(LOG_TAG "CalculateFileSha256.SetFilePointer failed. Error: %u",
dwError);
return ""; // Return empty string on failure
return ""; // Return empty string on failure
}

// Acquire Crypto Provider.
// Using CRYPT_VERIFYCONTEXT for operations that don't require private key access.
// Using CRYPT_VERIFYCONTEXT for operations that don't require private key
// access.
if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
DWORD dwError = GetLastError();
Expand Down Expand Up @@ -152,7 +153,8 @@ static std::string CalculateFileSha256(HANDLE hFile) {
// --- Get the binary hash value ---
DWORD cbHashValue = 0;
DWORD dwCount = sizeof(DWORD);
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashValue, &dwCount, 0)) {
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashValue, &dwCount,
0)) {
DWORD dwError = GetLastError();
LogError(LOG_TAG
"CalculateFileSha256.CryptGetHashParam (HP_HASHSIZE) failed. "
Expand All @@ -179,12 +181,13 @@ static std::string CalculateFileSha256(HANDLE hFile) {
// --- Convert the binary hash to a hex string ---
DWORD hex_string_size = 0;
if (!CryptBinaryToStringA(binary_hash_value.data(), binary_hash_value.size(),
CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF,
NULL, &hex_string_size)) {
CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, NULL,
&hex_string_size)) {
DWORD dwError = GetLastError();
LogError(LOG_TAG
"CalculateFileSha256.CryptBinaryToStringA (size) failed. Error: %u",
dwError);
LogError(
LOG_TAG
"CalculateFileSha256.CryptBinaryToStringA (size) failed. Error: %u",
dwError);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return "";
Expand All @@ -196,7 +199,8 @@ static std::string CalculateFileSha256(HANDLE hFile) {
&hex_hash_string[0], &hex_string_size)) {
DWORD dwError = GetLastError();
LogError(LOG_TAG
"CalculateFileSha256.CryptBinaryToStringA (conversion) failed. Error: %u",
"CalculateFileSha256.CryptBinaryToStringA (conversion) failed. "
"Error: %u",
dwError);
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
Expand Down Expand Up @@ -286,9 +290,9 @@ HMODULE VerifyAndLoadAnalyticsLibrary(
if (calculated_hash == expected_hash) {
hash_matched = true;
break;
}
else {
LogDebug(LOG_TAG "Hash mismatch: got %s expected %s", calculated_hash.c_str(), expected_hash.c_str());
} else {
LogDebug(LOG_TAG "Hash mismatch: got %s expected %s",
calculated_hash.c_str(), expected_hash.c_str());
}
}

Expand Down
Loading