Skip to content

Commit c2ce64d

Browse files
jonsimantovgoogle-labs-jules[bot]a-maurice
authored
Modify Analytics on desktop to use a verified DLL on Windows (although it is currently still a stub). (#1731)
* Here's the updated commit message: refactor: Remove stale comments and TODOs from Windows Analytics Cleans up src/analytics_desktop.cc by: - Removing outdated TODO comments related to header verification and type definitions (Parameter/Item) that have since been resolved. - Deleting informational comments that were no longer accurate after refactoring (e.g., comments about placeholder types, forward declarations for removed types). - Removing an empty anonymous namespace that previously held an internal type alias. This commit improves the readability and maintainability of the Windows Analytics implementation by removing distracting or misleading commentary. The TODO regarding the precise Future creation mechanism in stubbed functions remains, as it requires further investigation of Firebase internal APIs. * feat: Integrate Firebase logging for Windows Analytics Replaces placeholder comments with actual calls to LogError() and LogWarning() throughout the Windows Analytics implementation in src/analytics_desktop.cc. Key changes: - Added #include "firebase/log.h". - Updated error handling in LogEvent, ConvertParametersToGAParams, and SetUserProperty to use LogError() for invalid arguments or internal failures. - Updated warnings for unexpected data types or structures in event parameters to use LogWarning(). - Added LogWarning() calls to all stubbed functions (e.g., SetConsent, InitiateOnDeviceConversionMeasurement*, SetSessionTimeoutDuration) to inform developers that these operations are not supported and have no effect on the Windows platform. This change enhances the robustness and diagnosability of the Windows Analytics module by providing clear feedback through the Firebase logging system. * refactor: Update event parameter handling for map and vector types Based on explicit feedback, this commit fundamentally changes how Parameter values of type Map and Vector are processed in the Windows Analytics C++ SDK (in src/analytics_desktop.cc): 1. **Parameter values of type Vector (`param.value.is_vector()`):** - These are now treated as UNSUPPORTED for top-level event parameters on Desktop. - An error is logged, and the parameter is skipped. - The previous logic that interpreted a vector of maps as an item array has been removed from ConvertParametersToGAParams. 2. **Parameter values of type Map (`param.value.is_map()`):** - This case is now explicitly handled. - The key-value pairs of the input map are transformed into a GoogleAnalytics_ItemVector. - Each entry (key, value_variant) in your map becomes a distinct GoogleAnalytics_Item within this ItemVector. - Each such GoogleAnalytics_Item stores the original map key under a property named "name", and the original map value (which must be a primitive type) under a typed property (e.g., "int_value", "double_value", "string_value"). - This resulting ItemVector is then added to the event's parameters using the original Parameter's name. 3. **Comments:** - Code comments within ConvertParametersToGAParams have been updated to reflect this new processing logic. This change aligns the behavior with specific design requirements for how map and vector type parameters should be translated to the underlying Windows C API for Google Analytics. * refactor: Align Windows Analytics stubs with SDK patterns This commit incorporates detailed review feedback to align the Windows Analytics C++ implementation (src/analytics_desktop.cc) with common Firebase C++ SDK patterns for managing Futures and including headers. Key changes: 1. **Future Management for Stubbed APIs:** - Replaced the previous Future creation mechanism (MakeFuture) for stubbed functions (GetAnalyticsInstanceId, GetSessionId, and their LastResult counterparts) with the standard FutureData pattern. - Added a static FutureData instance (g_future_data), initialized in firebase::analytics::Initialize() and cleaned up in Terminate(). - Defined an internal AnalyticsFn enum for Future function tracking. - Stubbed Future-returning methods now use g_future_data to create and complete Futures. - As per feedback, these Futures are completed with error code 0 and a null error message. A LogWarning is now used to inform developers that the called API is not supported on Desktop. - Added checks for g_future_data initialization in these methods. 2. **Include Path Updates:** - Corrected #include paths for common Firebase headers (app.h, variant.h, future.h, log.h) to use full module-prefixed paths (e.g., "app/src/include/firebase/app.h") instead of direct "firebase/" paths. - Removed a stale include comment. These changes improve the consistency of the Windows Analytics stubs with the rest of the Firebase C++ SDK. * Here's the plan: refactor: Address further review comments for Windows Analytics This commit incorporates additional specific feedback on the Windows Analytics C++ implementation (src/analytics_desktop.cc): 1. **Comment Cleanup:** - Removed a commented-out unused constant and its description. - Removed a non-functional comment next to a namespace declaration. - Clarified and shortened the comment in the `is_vector` handling block within `ConvertParametersToGAParams`. 2. **Use Common `AnalyticsFn` Enum:** - Included `analytics/src/common/analytics_common.h`. - Removed the local definition of `AnalyticsFn` enum, now relying on the common definition (assumed to be in `firebase::analytics::internal`). 3. **Corrected Map Parameter to `GoogleAnalytics_Item` Conversion:** - Critically, fixed the logic in `ConvertParametersToGAParams` for when a `Parameter::value` is a map. - Previously, each key-value pair from the input map was incorrectly creating a `GoogleAnalytics_Item` with fixed property names like "name" and "int_value". - The logic now correctly ensures that each key-value pair from your input map becomes a direct property in the `GoogleAnalytics_Item`, using the original map's key as the key for the property in the `GoogleAnalytics_Item`. For example, an entry `{"user_key": 123}` in the input map now results in a property `{"user_key": 123}` within the `GoogleAnalytics_Item`. * refactor: Address final review comments for Windows Analytics This commit incorporates the latest round of specific feedback on the Windows Analytics C++ implementation (src/analytics_desktop.cc): 1. **Comment Cleanup:** - Removed a large commented-out block that previously contained a local `AnalyticsFn` enum definition. - Removed a comment in `Initialize()` related to marking the `app` parameter as unused. - Removed an outdated comment in `Initialize()` that described the function as a placeholder. - Removed a type comment from the `ConvertParametersToGAParams()` function signature. - Replaced a lengthy comment in `LogEvent()` regarding C API object lifecycle with a more concise one. 2. **Refined Map Parameter Processing Logic:** - In `ConvertParametersToGAParams`, when handling a `Parameter` whose value is a map, the logic for creating `GoogleAnalytics_Item` objects from the map's entries has been clarified. - A local boolean flag (`successfully_set_property`) is used for each map entry to track if a value was successfully set in the corresponding `GoogleAnalytics_Item`. - A `GoogleAnalytics_Item` is only added to the `GoogleAnalytics_ItemVector` if a property was successfully set. Otherwise, the item is destroyed. This prevents empty or partially formed items (e.g., from map entries with unsupported value types) from being included in the ItemVector. * chore: Relocate analytics_desktop.cc to analytics/src/ As per review feedback, this commit moves the Windows Analytics C++ implementation file from src/analytics_desktop.cc to analytics/src/analytics_desktop.cc. The content of the file remains the same as the previous version, incorporating all prior review feedback. I attempted to run the code formatter script after the move, but the script failed due to an internal error. Formatting was not applied. * Clean up generated code. * Update desktop code to fix issues. * Copy Analytics DLL from SDK directory. * Add wide string version of SetAnalyticsLibraryPath and export "publicly". * Update log messages. * Format code. * Update paths and remove old stub. * Update some nomenclature. * Add a SHA256 hash to verify on load. * Fix build error. * Add hash constant. * Update layout. * refactor: Rename library_path to library_filename for clarity Renamed the parameter `library_path` to `library_filename` in the `VerifyAndLoadAnalyticsLibrary` function (declaration in `analytics_windows.h` and definition and usage in `analytics_windows.cc`). This change improves clarity, as the parameter is expected to be only the DLL's filename, not a full path. The full path for file operations is constructed internally within the function using _wpgmptr and this filename. * Tweak errors and format code. * Revert to stubs on load fail. * Remove big comment. * Don't include analytics_windows.h except on Windows. If no hash is passed in, load the DLL indiscriminantly. * Add copyright notice. * Fixed log include. * Fix comment. * refactor: Extract GetExecutablePath helper in analytics_windows.cc I've refactored `VerifyAndLoadAnalyticsLibrary` in `analytics_windows.cc` to improve readability and modularity by extracting the logic for obtaining the executable's full path into a new static helper function `GetExecutablePath()`. - The new `GetExecutablePath()` function encapsulates the prioritized use of `_get_wpgmptr()`, fallback to `_get_pgmptr()`, and the necessary `MultiByteToWideChar` conversion, along with all associated error handling and logging. It returns `std::wstring`. - `VerifyAndLoadAnalyticsLibrary` now calls `GetExecutablePath()` and checks its return value before proceeding with path manipulation. - This change makes `VerifyAndLoadAnalyticsLibrary` shorter and easier to understand. All previous security enhancements and fixes are maintained. * refactor: Update log.h include path and extract GetExecutablePath helper This commit includes two main changes: 1. Updated the include path for `log.h` in `analytics_windows.cc` and `analytics_desktop.cc` from `app/src/include/firebase/log.h` to `app/src/log.h` for consistency. 2. Refactored `VerifyAndLoadAnalyticsLibrary` in `analytics_windows.cc` to improve readability and modularity by extracting the logic for obtaining the executable's full path into a new static helper function `GetExecutablePath()`. - The new `GetExecutablePath()` function encapsulates the prioritized use of `_get_wpgmptr()`, fallback to `_get_pgmptr()`, and the necessary `MultiByteToWideChar` conversion, along with all associated error handling and logging. It returns `std::wstring`. - `VerifyAndLoadAnalyticsLibrary` now calls `GetExecutablePath()` and checks its return value before proceeding with path manipulation. - This change makes `VerifyAndLoadAnalyticsLibrary` shorter and easier to understand. All previous security enhancements and fixes are maintained. * Updated formatting and errors. * Factor out log tag. * Format code. * Fix syntax error. * Refactor GetExecutablePath with two-tier buffer strategy This commit updates the GetExecutablePath function in analytics_windows.cc to use a two-tier buffer sizing strategy as per revised requirements. The function first attempts to retrieve the executable path using a buffer of MAX_PATH + 1 characters. If this fails due to an insufficient buffer (ERROR_INSUFFICIENT_BUFFER), it makes a second attempt with a larger buffer of 65536 characters. This approach replaces the previous iterative buffer resizing logic. Additionally, explicit try/catch blocks for std::bad_alloc have been removed in accordance with codebase guidelines. Error handling for GetModuleFileNameW API calls is maintained. * Clean up logic for getting executable path. * Format code. * Fix nesting. * Fix nesting again. * Use LoadLibraryW because LoadLibraryExW is failing. * Fix build error. * Add a warning. * Add an info message. * Fix error. * Change message to debug. * Move functions. * Delete DLL file with stubs. * Silence an unneeded error. * Revert "Delete DLL file with stubs." This reverts commit 7bfd4e3. * Change file format and move the hash out of non-Windows platforms. * Fix: Use sizeof for Analytics DLL hash array I changed the code in `analytics_desktop.cc` to use `sizeof(FirebaseAnalytics_WindowsDllHash)` when constructing the vector for the DLL hash. This replaces the previously hardcoded size of 32, making the code safer and more maintainable. * Refactor: Adjust log level for hash mismatch in analytics_windows I changed a LogVerbose call to LogDebug in `VerifyAndLoadAnalyticsLibrary` within `analytics/src/analytics_windows.cc`. The log message for a hash size mismatch when iterating through allowed hashes is now logged at Debug level instead of Verbose. * Format code. * Updated Analytics Windows to allow multiple DLL hashes, and add usage of Options struct. (#1744) * Update script and code to handle known hashes for multiple DLLs. * Fixed issues on Windows with multi-dll-hash code. * Fix: Link Crypt32.lib for firebase_analytics on Windows Add Crypt32.lib to the linked libraries for the firebase_analytics target on Windows. This resolves a linker error LNK2019 for _CryptBinaryToStringA@20, which was occurring in builds that included analytics_windows.obj (e.g., firebase_analytics_test). While CryptBinaryToStringA is not directly called in analytics_windows.cc, the linker indicates that analytics_windows.obj requires this symbol, possibly due to an indirect dependency or other build system interactions. Linking Crypt32.lib provides the necessary symbol. * Fix: Link Crypt32.lib for firebase_analytics_test on Windows I've added Crypt32.lib to the dependencies of the firebase_analytics_test target in `analytics/tests/CMakeLists.txt` when building on Windows. This is to resolve a persistent LNK2019 error for _CryptBinaryToStringA@20, which occurs during the linking phase of firebase_analytics_test.obj. This change directly links the required system library at the test executable level. * Update DLL. * Remove unused file. * Remove extra file. * 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. * Update stub generation. * Format code. * Fix build issues. * 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> * Format code. * Only display Analytics warnings if we are not in stub mode. * Format code. * Address review comments and add missing copyright notices. * Remove extraneous commented out code. * Add another known hash to the list. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> * Update analytics_desktop.cc --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: a-maurice <[email protected]>
1 parent e6e11bd commit c2ce64d

16 files changed

+1380
-250
lines changed

analytics/CMakeLists.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,15 @@ set(android_SRCS
7474
set(ios_SRCS
7575
src/analytics_ios.mm)
7676

77-
# Source files used by the stub implementation.
78-
set(stub_SRCS
79-
src/analytics_stub.cc)
77+
# Source files used by the desktop / stub implementation.
78+
set(desktop_SRCS
79+
src/analytics_desktop.cc
80+
src/analytics_desktop_dynamic.c)
81+
82+
if(WIN32)
83+
# Add Windows-specific sources for desktop builds.
84+
list(APPEND desktop_SRCS src/analytics_windows.cc)
85+
endif()
8086

8187
if(ANDROID)
8288
set(analytics_platform_SRCS
@@ -86,7 +92,7 @@ elseif(IOS)
8692
"${ios_SRCS}")
8793
else()
8894
set(analytics_platform_SRCS
89-
"${stub_SRCS}")
95+
"${desktop_SRCS}")
9096
endif()
9197

9298
add_library(firebase_analytics STATIC
@@ -98,6 +104,9 @@ set_property(TARGET firebase_analytics PROPERTY FOLDER "Firebase Cpp")
98104
# Set up the dependency on Firebase App.
99105
target_link_libraries(firebase_analytics
100106
PUBLIC firebase_app)
107+
if(WIN32)
108+
target_link_libraries(firebase_analytics PRIVATE Crypt32.lib)
109+
endif()
101110
# Public headers all refer to each other relative to the src/include directory,
102111
# while private headers are relative to the entire C++ SDK directory.
103112
target_include_directories(firebase_analytics

analytics/generate_windows_stubs.py

Lines changed: 91 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
"""Generate stubs and function pointers for Windows SDK"""
1717

1818
import argparse
19+
import hashlib
1920
import os
2021
import re
2122
import sys
2223

2324
HEADER_GUARD_PREFIX = "FIREBASE_ANALYTICS_SRC_WINDOWS_"
24-
INCLUDE_PATH = "src/windows/"
25+
INCLUDE_PATH = "src/"
2526
INCLUDE_PREFIX = "analytics/" + INCLUDE_PATH
2627
COPYRIGHT_NOTICE = """// Copyright 2025 Google LLC
2728
//
@@ -39,17 +40,50 @@
3940
4041
"""
4142

42-
def generate_function_pointers(header_file_path, output_h_path, output_c_path):
43+
44+
def hash_file(filename):
45+
sha256_hash = hashlib.sha256()
46+
with open(filename, "rb") as file:
47+
while chunk := file.read(4096):
48+
sha256_hash.update(chunk)
49+
return sha256_hash.digest()
50+
51+
def generate_function_pointers(dll_file_path, header_file_path, output_h_path, output_c_path):
4352
"""
4453
Parses a C header file to generate a self-contained header with typedefs,
4554
extern function pointer declarations, and a source file with stub functions,
4655
initialized pointers, and a dynamic loading function for Windows.
4756
4857
Args:
58+
dll_file_path (str): The path to the DLL file.
4959
header_file_path (str): The path to the input C header file.
5060
output_h_path (str): The path for the generated C header output file.
5161
output_c_path (str): The path for the generated C source output file.
5262
"""
63+
print(f"Reading DLL file: {dll_file_path}")
64+
dll_hash = hash_file(dll_file_path) # This is binary
65+
66+
# --- Manage known hashes ---
67+
hash_file_path = os.path.join(os.path.dirname(dll_file_path), "known_dll_hashes.txt")
68+
known_hex_hashes = []
69+
try:
70+
with open(hash_file_path, 'r') as f:
71+
for line in f:
72+
known_hex_hashes.append(line.strip())
73+
except FileNotFoundError:
74+
print(f"Info: '{hash_file_path}' not found, will be created.")
75+
pass # File doesn't exist, list remains empty
76+
77+
current_dll_hex_hash = dll_hash.hex()
78+
if current_dll_hex_hash not in known_hex_hashes:
79+
known_hex_hashes.append(current_dll_hex_hash)
80+
81+
with open(hash_file_path, 'w') as f:
82+
for hex_hash in known_hex_hashes:
83+
f.write(hex_hash + '\n')
84+
print(f"Updated known hashes in: {hash_file_path}")
85+
# --- End of manage known hashes ---
86+
5387
print(f"Reading header file: {header_file_path}")
5488
try:
5589
with open(header_file_path, 'r', encoding='utf-8') as f:
@@ -64,7 +98,7 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
6498
includes = re.findall(r"#include\s+<.*?>", header_content)
6599

66100
# Find all typedefs, including their documentation comments
67-
typedefs = re.findall(r"/\*\*(?:[\s\S]*?)\*/\s*typedef[\s\S]*?;\s*", header_content)
101+
typedefs = re.findall(r"(?:/\*\*(?:[\s\S]*?)\*/\s*)?typedef[\s\S]*?;\s*", header_content)
68102

69103
# --- Extract function prototypes ---
70104
function_pattern = re.compile(
@@ -83,18 +117,18 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
83117
return_type = match.group(1).strip()
84118
function_name = match.group(2).strip()
85119
params_str = match.group(3).strip()
86-
120+
87121
cleaned_params_for_decl = re.sub(r'\s+', ' ', params_str) if params_str else ""
88122
stub_name = f"Stub_{function_name}"
89123

90124
# Generate return statement for the stub
91125
if "void" in return_type:
92126
return_statement = " // No return value."
93127
elif "*" in return_type:
94-
return_statement = f' return ({return_type})(&g_stub_memory);'
128+
return_statement = f' return ({return_type})(&g_stub_memory[0]);'
95129
else: # bool, int64_t, etc.
96130
return_statement = " return 1;"
97-
131+
98132
stub_function = (
99133
f"// Stub for {function_name}\n"
100134
f"static {return_type} {stub_name}({params_str}) {{\n"
@@ -111,7 +145,7 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
111145

112146
pointer_init = f"{return_type} (*ptr_{function_name})({cleaned_params_for_decl}) = &{stub_name};"
113147
pointer_initializations.append(pointer_init)
114-
148+
115149
function_details_for_loader.append((function_name, return_type, cleaned_params_for_decl))
116150

117151
print(f"Found {len(pointer_initializations)} functions. Generating output files...")
@@ -123,13 +157,14 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
123157
f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n")
124158
f.write(f"#ifndef {header_guard}\n")
125159
f.write(f"#define {header_guard}\n\n")
160+
f.write(f"#define ANALYTICS_API // filter out from header copy\n\n")
126161
f.write("#include <stdbool.h> // needed for bool type in pure C\n\n")
127-
162+
128163
f.write("// --- Copied from original header ---\n")
129164
f.write("\n".join(includes) + "\n\n")
130165
f.write("".join(typedefs))
131166
f.write("// --- End of copied section ---\n\n")
132-
167+
133168
f.write("#ifdef __cplusplus\n")
134169
f.write('extern "C" {\n')
135170
f.write("#endif\n\n")
@@ -139,15 +174,21 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
139174
f.write("\n\n")
140175
f.write("\n".join(macro_definitions))
141176
f.write("\n// clang-format on\n")
142-
f.write("\n\n// --- Dynamic Loader Declaration for Windows ---\n")
143-
f.write("#if defined(_WIN32)\n")
144-
f.write('#include <windows.h> // For HMODULE\n')
145-
f.write('// Load Google Analytics functions from the given DLL handle into function pointers.\n')
146-
f.write(f'// Returns the number of functions successfully loaded (out of {len(function_details_for_loader)}).\n')
147-
f.write("int FirebaseAnalytics_LoadAnalyticsFunctions(HMODULE dll_handle);\n\n")
177+
f.write(f'\n// Number of Google Analytics functions expected to be loaded from the DLL.')
178+
f.write('\nextern const int FirebaseAnalytics_DynamicFunctionCount;\n');
179+
f.write("\n// --- Dynamic Loader Declaration for Windows ---\n")
180+
f.write("#if defined(_WIN32)\n\n")
181+
f.write('#include <windows.h>\n')
182+
f.write('\n// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings).\n')
183+
f.write('extern const char* FirebaseAnalytics_KnownWindowsDllHashes[];\n')
184+
f.write('// Count of known Google Analytics Windows DLL SHA256 hashes.\n')
185+
f.write('extern const int FirebaseAnalytics_KnownWindowsDllHashCount;\n\n')
186+
f.write('// Load Analytics functions from the given DLL handle into function pointers.\n')
187+
f.write(f'// Returns the number of functions successfully loaded.\n')
188+
f.write("int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle);\n\n")
148189
f.write('// Reset all function pointers back to stubs.\n')
149-
f.write("void FirebaseAnalytics_UnloadAnalyticsFunctions(void);\n\n")
150-
f.write("#endif // defined(_WIN32)\n")
190+
f.write("void FirebaseAnalytics_UnloadDynamicFunctions(void);\n\n")
191+
f.write("#endif // defined(_WIN32)\n")
151192
f.write("\n#ifdef __cplusplus\n")
152193
f.write("}\n")
153194
f.write("#endif\n\n")
@@ -159,18 +200,34 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
159200
with open(output_c_path, 'w', encoding='utf-8') as f:
160201
f.write(f"{COPYRIGHT_NOTICE}")
161202
f.write(f"// Generated from {os.path.basename(header_file_path)} by {os.path.basename(sys.argv[0])}\n\n")
162-
f.write(f'#include "{INCLUDE_PREFIX}{os.path.basename(output_h_path)}"\n')
203+
f.write(f'#include "{INCLUDE_PREFIX}{os.path.basename(output_h_path)}"\n\n')
163204
f.write('#include <stddef.h>\n\n')
164-
f.write("// clang-format off\n\n")
165-
f.write("static void* g_stub_memory = NULL;\n\n")
166-
f.write("// --- Stub Function Definitions ---\n")
205+
f.write("// A nice big chunk of stub memory that can be returned by stubbed Create methods.\n")
206+
f.write("static char g_stub_memory[256] = {0};\n\n")
207+
f.write("// clang-format off\n")
208+
f.write(f'\n// Number of Google Analytics functions expected to be loaded from the DLL.')
209+
f.write(f'\nconst int FirebaseAnalytics_DynamicFunctionCount = {len(function_details_for_loader)};\n\n');
210+
f.write("#if defined(_WIN32)\n")
211+
f.write('// Array of known Google Analytics Windows DLL SHA256 hashes (hex strings).\n')
212+
f.write('const char* FirebaseAnalytics_KnownWindowsDllHashes[] = {\n')
213+
if known_hex_hashes:
214+
for i, hex_hash in enumerate(known_hex_hashes):
215+
f.write(f' "{hex_hash}"')
216+
if i < len(known_hex_hashes) - 1:
217+
f.write(',')
218+
f.write('\n')
219+
f.write('};\n\n')
220+
f.write('// Count of known Google Analytics Windows DLL SHA256 hashes.\n')
221+
f.write(f'const int FirebaseAnalytics_KnownWindowsDllHashCount = {len(known_hex_hashes)};\n')
222+
f.write("#endif // defined(_WIN32)\n")
223+
f.write("\n// --- Stub Function Definitions ---\n")
167224
f.write("\n\n".join(stub_functions))
168225
f.write("\n\n\n// --- Function Pointer Initializations ---\n")
169226
f.write("\n".join(pointer_initializations))
170227
f.write("\n\n// --- Dynamic Loader Function for Windows ---\n")
171228
loader_lines = [
172229
'#if defined(_WIN32)',
173-
'int FirebaseAnalytics_LoadAnalyticsFunctions(HMODULE dll_handle) {',
230+
'int FirebaseAnalytics_LoadDynamicFunctions(HMODULE dll_handle) {',
174231
' int count = 0;\n',
175232
' if (!dll_handle) {',
176233
' return count;',
@@ -188,7 +245,7 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
188245
loader_lines.extend(proc_check)
189246
loader_lines.append('\n return count;')
190247
loader_lines.append('}\n')
191-
loader_lines.append('void FirebaseAnalytics_UnloadAnalyticsFunctions(void) {')
248+
loader_lines.append('void FirebaseAnalytics_UnloadDynamicFunctions(void) {')
192249
for name, ret_type, params in function_details_for_loader:
193250
loader_lines.append(f' ptr_{name} = &Stub_{name};');
194251
loader_lines.append('}\n')
@@ -203,29 +260,31 @@ def generate_function_pointers(header_file_path, output_h_path, output_c_path):
203260
parser = argparse.ArgumentParser(
204261
description="Generate C stubs and function pointers from a header file."
205262
)
263+
parser.add_argument(
264+
"--windows_dll",
265+
default = os.path.join(os.path.dirname(sys.argv[0]), "windows/analytics_win.dll"),
266+
help="Path to the DLL file to calculate a hash."
267+
)
206268
parser.add_argument(
207269
"--windows_header",
208270
default = os.path.join(os.path.dirname(sys.argv[0]), "windows/include/public/c/analytics.h"),
209-
#required=True,
210271
help="Path to the input C header file."
211272
)
212273
parser.add_argument(
213274
"--output_header",
214-
default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_dynamic.h"),
215-
#required=True,
275+
default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_desktop_dynamic.h"),
216276
help="Path for the generated output header file."
217277
)
218278
parser.add_argument(
219279
"--output_source",
220-
default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_dynamic.c"),
221-
#required=True,
280+
default = os.path.join(os.path.dirname(sys.argv[0]), INCLUDE_PATH, "analytics_desktop_dynamic.c"),
222281
help="Path for the generated output source file."
223282
)
224-
225283
args = parser.parse_args()
226-
284+
227285
generate_function_pointers(
228-
args.windows_header,
229-
args.output_header,
286+
args.windows_dll,
287+
args.windows_header,
288+
args.output_header,
230289
args.output_source
231290
)

analytics/integration_test/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ else()
211211
)
212212
elseif(MSVC)
213213
set(ADDITIONAL_LIBS advapi32 ws2_32 crypt32)
214+
set(ANALYTICS_WINDOWS_DLL "${FIREBASE_CPP_SDK_DIR}/analytics/windows/analytics_win.dll")
215+
216+
# For Windows, check if the Analytics DLL exists, and copy it in if so.
217+
if (EXISTS "${ANALYTICS_WINDOWS_DLL}")
218+
add_custom_command(
219+
TARGET ${integration_test_target_name} POST_BUILD
220+
COMMAND ${CMAKE_COMMAND} -E copy
221+
"${ANALYTICS_WINDOWS_DLL}"
222+
$<TARGET_FILE_DIR:${integration_test_target_name}>)
223+
endif()
214224
else()
215225
set(ADDITIONAL_LIBS pthread)
216226
endif()

0 commit comments

Comments
 (0)