Skip to content

Commit 90c33e4

Browse files
authored
[Rollouts] Feature rollouts merge to main (#12410)
1 parent 07b7669 commit 90c33e4

File tree

73 files changed

+3281
-177
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3281
-177
lines changed

CoreOnly/Tests/FirebasePodTest/Podfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ target 'FirebasePodTest' do
3333
pod 'FirebaseAppCheckInterop', :path => '../../../'
3434
pod 'FirebaseAuthInterop', :path => '../../../'
3535
pod 'FirebaseMessagingInterop', :path => '../../../'
36+
pod 'FirebaseRemoteConfigInterop', :path => '../../../'
3637
pod 'FirebaseCoreInternal', :path => '../../../'
3738
pod 'FirebaseCoreExtension', :path => '../../../'
3839
pod 'FirebaseSessions', :path => '../../../'

Crashlytics/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22
- [added] Updated upload-symbols to 13.7 with VisionPro build phase support. (#12306)
3+
- [changed] Added support for Crashlytics to report metadata about Remote Config keys and values.
34

45
# 10.22.0
56
- [fixed] Force validation or rotation of FIDs for FirebaseSessions.

Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary* keysAndValues);
8181
void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value);
8282
void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value);
8383

84-
void FIRCLSUserLoggingRecordError(NSError* error, NSDictionary<NSString*, id>* additionalUserInfo);
84+
void FIRCLSUserLoggingRecordError(NSError* error,
85+
NSDictionary<NSString*, id>* additionalUserInfo,
86+
NSString* rolloutsInfoJSON);
8587

8688
NSDictionary* FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage* storage,
8789
bool decodeHex);

Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,8 @@ static void FIRCLSUserLoggingWriteError(FIRCLSFile *file,
355355
NSError *error,
356356
NSDictionary<NSString *, id> *additionalUserInfo,
357357
NSArray *addresses,
358-
uint64_t timestamp) {
358+
uint64_t timestamp,
359+
NSString *rolloutsInfoJSON) {
359360
FIRCLSFileWriteSectionStart(file, "error");
360361
FIRCLSFileWriteHashStart(file);
361362
FIRCLSFileWriteHashEntryHexEncodedString(file, "domain", [[error domain] UTF8String]);
@@ -374,12 +375,20 @@ static void FIRCLSUserLoggingWriteError(FIRCLSFile *file,
374375
FIRCLSUserLoggingRecordErrorUserInfo(file, "info", [error userInfo]);
375376
FIRCLSUserLoggingRecordErrorUserInfo(file, "extra_info", additionalUserInfo);
376377

378+
// rollouts
379+
if (rolloutsInfoJSON) {
380+
FIRCLSFileWriteHashKey(file, "rollouts");
381+
FIRCLSFileWriteStringUnquoted(file, [rolloutsInfoJSON UTF8String]);
382+
FIRCLSFileWriteHashEnd(file);
383+
}
384+
377385
FIRCLSFileWriteHashEnd(file);
378386
FIRCLSFileWriteSectionEnd(file);
379387
}
380388

381389
void FIRCLSUserLoggingRecordError(NSError *error,
382-
NSDictionary<NSString *, id> *additionalUserInfo) {
390+
NSDictionary<NSString *, id> *additionalUserInfo,
391+
NSString *rolloutsInfoJSON) {
383392
if (!error) {
384393
return;
385394
}
@@ -396,7 +405,8 @@ void FIRCLSUserLoggingRecordError(NSError *error,
396405
FIRCLSUserLoggingWriteAndCheckABFiles(
397406
&_firclsContext.readonly->logging.errorStorage,
398407
&_firclsContext.writable->logging.activeErrorLogPath, ^(FIRCLSFile *file) {
399-
FIRCLSUserLoggingWriteError(file, error, additionalUserInfo, addresses, timestamp);
408+
FIRCLSUserLoggingWriteError(file, error, additionalUserInfo, addresses, timestamp,
409+
rolloutsInfoJSON);
400410
});
401411
}
402412

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#if SWIFT_PACKAGE
16+
@import FirebaseCrashlyticsSwift;
17+
#else // Swift Package Manager
18+
#import <FirebaseCrashlytics/FirebaseCrashlytics-Swift.h>
19+
#endif // CocoaPods
20+
21+
@interface FIRCLSRolloutsPersistenceManager : NSObject <FIRCLSPersistenceLog>
22+
23+
- (instancetype _Nullable)initWithFileManager:(FIRCLSFileManager *_Nonnull)fileManager;
24+
- (instancetype _Nonnull)init NS_UNAVAILABLE;
25+
+ (instancetype _Nonnull)new NS_UNAVAILABLE;
26+
27+
- (void)updateRolloutsStateToPersistenceWithRollouts:(NSData *_Nonnull)rollouts
28+
reportID:(NSString *_Nonnull)reportID;
29+
- (void)debugLogWithMessage:(NSString *_Nonnull)message;
30+
@end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import <Foundation/Foundation.h>
16+
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
17+
#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
18+
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
19+
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
20+
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
21+
22+
#if SWIFT_PACKAGE
23+
@import FirebaseCrashlyticsSwift;
24+
#else // Swift Package Manager
25+
#import <FirebaseCrashlytics/FirebaseCrashlytics-Swift.h>
26+
#endif // CocoaPods
27+
28+
@interface FIRCLSRolloutsPersistenceManager : NSObject <FIRCLSPersistenceLog>
29+
@property(nonatomic, readonly) FIRCLSFileManager *fileManager;
30+
@end
31+
32+
@implementation FIRCLSRolloutsPersistenceManager
33+
- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager {
34+
self = [super init];
35+
if (!self) {
36+
return nil;
37+
}
38+
_fileManager = fileManager;
39+
return self;
40+
}
41+
42+
- (void)updateRolloutsStateToPersistenceWithRollouts:(NSData *_Nonnull)rollouts
43+
reportID:(NSString *_Nonnull)reportID {
44+
NSString *rolloutsPath = [[[_fileManager activePath] stringByAppendingPathComponent:reportID]
45+
stringByAppendingPathComponent:FIRCLSReportRolloutsFile];
46+
if (![_fileManager fileExistsAtPath:rolloutsPath]) {
47+
if (![_fileManager createFileAtPath:rolloutsPath contents:nil attributes:nil]) {
48+
FIRCLSDebugLog(@"Could not create rollouts.clsrecord file. Error was code: %d - message: %s",
49+
errno, strerror(errno));
50+
}
51+
}
52+
53+
NSFileHandle *rolloutsFile = [NSFileHandle fileHandleForUpdatingAtPath:rolloutsPath];
54+
55+
dispatch_sync(FIRCLSGetLoggingQueue(), ^{
56+
[rolloutsFile seekToEndOfFile];
57+
[rolloutsFile writeData:rollouts];
58+
NSData *newLineData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
59+
[rolloutsFile writeData:newLineData];
60+
});
61+
}
62+
63+
- (void)debugLogWithMessage:(NSString *_Nonnull)message {
64+
FIRCLSDebugLog(message);
65+
}
66+
67+
@end

Crashlytics/Crashlytics/FIRCrashlytics.m

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
3232
#include "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"
3333
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
34+
#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h"
3435
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
3536
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
3637
#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h"
@@ -47,6 +48,7 @@
4748
#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h"
4849
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h"
4950
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
51+
#import "Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.h"
5052
#import "Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h"
5153
#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"
5254
#import "Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h"
@@ -58,6 +60,12 @@
5860
#import <GoogleDataTransport/GoogleDataTransport.h>
5961

6062
@import FirebaseSessions;
63+
@import FirebaseRemoteConfigInterop;
64+
#if SWIFT_PACKAGE
65+
@import FirebaseCrashlyticsSwift;
66+
#else // Swift Package Manager
67+
#import <FirebaseCrashlytics/FirebaseCrashlytics-Swift.h>
68+
#endif // CocoaPods
6169

6270
#if TARGET_OS_IPHONE
6371
#import <UIKit/UIKit.h>
@@ -76,7 +84,10 @@
7684
@protocol FIRCrashlyticsInstanceProvider <NSObject>
7785
@end
7886

79-
@interface FIRCrashlytics () <FIRLibrary, FIRCrashlyticsInstanceProvider, FIRSessionsSubscriber>
87+
@interface FIRCrashlytics () <FIRLibrary,
88+
FIRCrashlyticsInstanceProvider,
89+
FIRSessionsSubscriber,
90+
FIRRolloutsStateSubscriber>
8091

8192
@property(nonatomic) BOOL didPreviouslyCrash;
8293
@property(nonatomic, copy) NSString *googleAppID;
@@ -91,6 +102,8 @@ @interface FIRCrashlytics () <FIRLibrary, FIRCrashlyticsInstanceProvider, FIRSes
91102

92103
@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager;
93104

105+
@property(nonatomic, strong) FIRCLSRemoteConfigManager *remoteConfigManager;
106+
94107
// Dependencies common to each of the Controllers
95108
@property(nonatomic, strong) FIRCLSManagerData *managerData;
96109

@@ -104,7 +117,8 @@ - (instancetype)initWithApp:(FIRApp *)app
104117
appInfo:(NSDictionary *)appInfo
105118
installations:(FIRInstallations *)installations
106119
analytics:(id<FIRAnalyticsInterop>)analytics
107-
sessions:(id<FIRSessionsProvider>)sessions {
120+
sessions:(id<FIRSessionsProvider>)sessions
121+
remoteConfig:(id<FIRRemoteConfigInterop>)remoteConfig {
108122
self = [super init];
109123

110124
if (self) {
@@ -189,8 +203,19 @@ - (instancetype)initWithApp:(FIRApp *)app
189203
}] catch:^void(NSError *error) {
190204
FIRCLSErrorLog(@"Crash reporting failed to initialize with error: %@", error);
191205
}];
192-
}
193206

207+
// RemoteConfig subscription should be made after session report directory created.
208+
if (remoteConfig) {
209+
FIRCLSDebugLog(@"Registering RemoteConfig SDK subscription for rollouts data");
210+
211+
FIRCLSRolloutsPersistenceManager *persistenceManager =
212+
[[FIRCLSRolloutsPersistenceManager alloc] initWithFileManager:_fileManager];
213+
_remoteConfigManager =
214+
[[FIRCLSRemoteConfigManager alloc] initWithRemoteConfig:remoteConfig
215+
persistenceDelegate:persistenceManager];
216+
[remoteConfig registerRolloutsStateSubscriber:self for:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform];
217+
}
218+
}
194219
return self;
195220
}
196221

@@ -215,6 +240,7 @@ + (void)load {
215240

216241
id<FIRAnalyticsInterop> analytics = FIR_COMPONENT(FIRAnalyticsInterop, container);
217242
id<FIRSessionsProvider> sessions = FIR_COMPONENT(FIRSessionsProvider, container);
243+
id<FIRRemoteConfigInterop> remoteConfig = FIR_COMPONENT(FIRRemoteConfigInterop, container);
218244

219245
FIRInstallations *installations = [FIRInstallations installationsWithApp:container.app];
220246

@@ -224,7 +250,8 @@ + (void)load {
224250
appInfo:NSBundle.mainBundle.infoDictionary
225251
installations:installations
226252
analytics:analytics
227-
sessions:sessions];
253+
sessions:sessions
254+
remoteConfig:remoteConfig];
228255
};
229256

230257
FIRComponent *component =
@@ -377,11 +404,13 @@ - (void)recordError:(NSError *)error {
377404
}
378405

379406
- (void)recordError:(NSError *)error userInfo:(NSDictionary<NSString *, id> *)userInfo {
380-
FIRCLSUserLoggingRecordError(error, userInfo);
407+
NSString *rolloutsInfoJSON = [_remoteConfigManager getRolloutAssignmentsEncodedJsonString];
408+
FIRCLSUserLoggingRecordError(error, userInfo, rolloutsInfoJSON);
381409
}
382410

383411
- (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel {
384-
FIRCLSExceptionRecordModel(exceptionModel);
412+
NSString *rolloutsInfoJSON = [_remoteConfigManager getRolloutAssignmentsEncodedJsonString];
413+
FIRCLSExceptionRecordModel(exceptionModel, rolloutsInfoJSON);
385414
}
386415

387416
- (void)recordOnDemandExceptionModel:(FIRExceptionModel *)exceptionModel {
@@ -407,4 +436,14 @@ - (FIRSessionsSubscriberName)sessionsSubscriberName {
407436
return FIRSessionsSubscriberNameCrashlytics;
408437
}
409438

439+
#pragma mark - FIRRolloutsStateSubscriber
440+
- (void)rolloutsStateDidChange:(FIRRolloutsState *_Nonnull)rolloutsState {
441+
if (!_remoteConfigManager) {
442+
FIRCLSDebugLog(@"rolloutsStateDidChange gets called without init the rc manager.");
443+
return;
444+
}
445+
NSString *currentReportID = _managerData.executionIDModel.executionID;
446+
[_remoteConfigManager updateRolloutsStateWithRolloutsState:rolloutsState
447+
reportID:currentReportID];
448+
}
410449
@end

Crashlytics/Crashlytics/Handlers/FIRCLSException.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,16 @@ void FIRCLSExceptionRaiseTestObjCException(void) __attribute((noreturn));
6060
void FIRCLSExceptionRaiseTestCppException(void) __attribute((noreturn));
6161

6262
#ifdef __OBJC__
63-
void FIRCLSExceptionRecordModel(FIRExceptionModel* exceptionModel);
63+
void FIRCLSExceptionRecordModel(FIRExceptionModel* exceptionModel, NSString* rolloutsInfoJSON);
6464
NSString* FIRCLSExceptionRecordOnDemandModel(FIRExceptionModel* exceptionModel,
6565
int previousRecordedOnDemandExceptions,
6666
int previousDroppedOnDemandExceptions);
6767
void FIRCLSExceptionRecordNSException(NSException* exception);
6868
void FIRCLSExceptionRecord(FIRCLSExceptionType type,
6969
const char* name,
7070
const char* reason,
71-
NSArray<FIRStackFrame*>* frames);
71+
NSArray<FIRStackFrame*>* frames,
72+
NSString* rolloutsInfoJSON);
7273
NSString* FIRCLSExceptionRecordOnDemand(FIRCLSExceptionType type,
7374
const char* name,
7475
const char* reason,

0 commit comments

Comments
 (0)