Skip to content

Commit fcd9aaa

Browse files
Update Analytics to use new options struct. (#1745)
* Initialize Analytics C SDK with AppOptions on desktop This change updates the desktop analytics initialization to use the newly required Options struct for the Windows C API. - In `analytics/src/analytics_desktop.cc`: - `firebase::analytics::Initialize(const App& app)` now retrieves `app_id` and `package_name` from `app.options()`. - It calls `GoogleAnalytics_Options_Create()` to create the options struct. - Populates `app_id`, `package_name`, and sets a default for `analytics_collection_enabled_at_first_launch`. - Calls `GoogleAnalytics_Initialize()` with the populated options struct. - String lifetimes for `app_id` and `package_name` are handled by creating local `std::string` copies before passing their `c_str()` to the C API. * Format code. * Fix build issues. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent cfa4385 commit fcd9aaa

File tree

4 files changed

+69
-23
lines changed

4 files changed

+69
-23
lines changed

analytics/generate_windows_stubs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ def generate_function_pointers(dll_file_path, header_file_path, output_h_path, o
159159
f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n")
160160
f.write(f"#ifndef {header_guard}\n")
161161
f.write(f"#define {header_guard}\n\n")
162+
f.write(f"#define ANALYTICS_API // filter out from header copy\n\n")
162163
f.write("#include <stdbool.h> // needed for bool type in pure C\n\n")
163164

164165
f.write("// --- Copied from original header ---\n")

analytics/src/analytics_desktop.cc

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828

2929
#if defined(_WIN32)
3030
#include <windows.h>
31-
32-
#include "analytics/src/analytics_windows.h"
31+
#include "analytics_windows.h"
3332
#endif // defined(_WIN32)
3433

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

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

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

5760
g_initialized = true;
5861
internal::RegisterTerminateOnDefaultAppDestroy();
@@ -62,17 +65,18 @@ void Initialize(const App& app) {
6265
#if defined(_WIN32)
6366
if (!g_analytics_module) {
6467
std::vector<std::string> allowed_hashes;
65-
for (int i=0; i < FirebaseAnalytics_KnownWindowsDllHashCount; i++) {
66-
allowed_hashes.push_back(std::string(FirebaseAnalytics_KnownWindowsDllHashes[i]));
68+
for (int i = 0; i < FirebaseAnalytics_KnownWindowsDllHashCount; i++) {
69+
allowed_hashes.push_back(
70+
std::string(FirebaseAnalytics_KnownWindowsDllHashes[i]));
6771
}
6872

6973
g_analytics_module =
7074
firebase::analytics::internal::VerifyAndLoadAnalyticsLibrary(
7175
ANALYTICS_DLL_FILENAME, allowed_hashes);
7276

7377
if (g_analytics_module) {
74-
int num_loaded = FirebaseAnalytics_LoadDynamicFunctions(
75-
g_analytics_module); // Ensure g_analytics_module is used
78+
int num_loaded =
79+
FirebaseAnalytics_LoadDynamicFunctions(g_analytics_module);
7680
if (num_loaded < FirebaseAnalytics_DynamicFunctionCount) {
7781
LogWarning(
7882
"Analytics: Failed to load functions from Google Analytics "
@@ -81,12 +85,47 @@ void Initialize(const App& app) {
8185
FirebaseAnalytics_UnloadDynamicFunctions();
8286
FreeLibrary(g_analytics_module);
8387
g_analytics_module = 0;
88+
// Do not proceed with C API initialization if functions didn't load
8489
} else {
8590
LogInfo("Analytics: Loaded Google Analytics module.");
91+
92+
// Initialize Google Analytics C API
93+
std::string current_app_id = app.options().app_id();
94+
std::string current_package_name = app.options().package_name();
95+
96+
GoogleAnalytics_Options* c_options = GoogleAnalytics_Options_Create();
97+
if (!c_options) {
98+
LogError("Analytics: Failed to create GoogleAnalytics_Options.");
99+
} else {
100+
c_options->app_id = current_app_id.c_str();
101+
c_options->package_name = current_package_name.c_str();
102+
c_options->analytics_collection_enabled_at_first_launch = true;
103+
// c_options->reserved is initialized by
104+
// GoogleAnalytics_Options_Create
105+
106+
LogInfo(
107+
"Analytics: Initializing Google Analytics C API with App ID: %s, "
108+
"Package Name: %s",
109+
c_options->app_id ? c_options->app_id : "null",
110+
c_options->package_name ? c_options->package_name : "null");
111+
112+
if (!GoogleAnalytics_Initialize(c_options)) {
113+
LogError("Analytics: Failed to initialize Google Analytics C API.");
114+
// GoogleAnalytics_Initialize destroys c_options automatically if
115+
// created by _Create
116+
} else {
117+
LogInfo(
118+
"Analytics: Google Analytics C API initialized successfully.");
119+
}
120+
}
86121
}
122+
} else {
123+
// LogWarning for g_analytics_module load failure is handled by
124+
// VerifyAndLoadAnalyticsLibrary
125+
g_analytics_module = 0; // Ensure it's null if loading failed
87126
}
88127
}
89-
#endif
128+
#endif // defined(_WIN32)
90129
}
91130

92131
namespace internal {

analytics/src/analytics_desktop_dynamic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#ifndef FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_
1818
#define FIREBASE_ANALYTICS_SRC_WINDOWS_ANALYTICS_DESKTOP_DYNAMIC_H_
1919

20+
#define ANALYTICS_API // filter out from header copy
21+
2022
#include <stdbool.h> // needed for bool type in pure C
2123

2224
// --- Copied from original header ---

analytics/src/analytics_windows.cc

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ static std::string CalculateFileSha256(HANDLE hFile) {
9999
DWORD dwError = GetLastError();
100100
LogError(LOG_TAG "CalculateFileSha256.SetFilePointer failed. Error: %u",
101101
dwError);
102-
return ""; // Return empty string on failure
102+
return ""; // Return empty string on failure
103103
}
104104

105105
// Acquire Crypto Provider.
106-
// Using CRYPT_VERIFYCONTEXT for operations that don't require private key access.
106+
// Using CRYPT_VERIFYCONTEXT for operations that don't require private key
107+
// access.
107108
if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES,
108109
CRYPT_VERIFYCONTEXT)) {
109110
DWORD dwError = GetLastError();
@@ -152,7 +153,8 @@ static std::string CalculateFileSha256(HANDLE hFile) {
152153
// --- Get the binary hash value ---
153154
DWORD cbHashValue = 0;
154155
DWORD dwCount = sizeof(DWORD);
155-
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashValue, &dwCount, 0)) {
156+
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashValue, &dwCount,
157+
0)) {
156158
DWORD dwError = GetLastError();
157159
LogError(LOG_TAG
158160
"CalculateFileSha256.CryptGetHashParam (HP_HASHSIZE) failed. "
@@ -179,12 +181,13 @@ static std::string CalculateFileSha256(HANDLE hFile) {
179181
// --- Convert the binary hash to a hex string ---
180182
DWORD hex_string_size = 0;
181183
if (!CryptBinaryToStringA(binary_hash_value.data(), binary_hash_value.size(),
182-
CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF,
183-
NULL, &hex_string_size)) {
184+
CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF, NULL,
185+
&hex_string_size)) {
184186
DWORD dwError = GetLastError();
185-
LogError(LOG_TAG
186-
"CalculateFileSha256.CryptBinaryToStringA (size) failed. Error: %u",
187-
dwError);
187+
LogError(
188+
LOG_TAG
189+
"CalculateFileSha256.CryptBinaryToStringA (size) failed. Error: %u",
190+
dwError);
188191
CryptDestroyHash(hHash);
189192
CryptReleaseContext(hProv, 0);
190193
return "";
@@ -196,7 +199,8 @@ static std::string CalculateFileSha256(HANDLE hFile) {
196199
&hex_hash_string[0], &hex_string_size)) {
197200
DWORD dwError = GetLastError();
198201
LogError(LOG_TAG
199-
"CalculateFileSha256.CryptBinaryToStringA (conversion) failed. Error: %u",
202+
"CalculateFileSha256.CryptBinaryToStringA (conversion) failed. "
203+
"Error: %u",
200204
dwError);
201205
CryptDestroyHash(hHash);
202206
CryptReleaseContext(hProv, 0);
@@ -286,9 +290,9 @@ HMODULE VerifyAndLoadAnalyticsLibrary(
286290
if (calculated_hash == expected_hash) {
287291
hash_matched = true;
288292
break;
289-
}
290-
else {
291-
LogDebug(LOG_TAG "Hash mismatch: got %s expected %s", calculated_hash.c_str(), expected_hash.c_str());
293+
} else {
294+
LogDebug(LOG_TAG "Hash mismatch: got %s expected %s",
295+
calculated_hash.c_str(), expected_hash.c_str());
292296
}
293297
}
294298

0 commit comments

Comments
 (0)