Skip to content

Commit f8b7ddd

Browse files
ivolivol
authored andcommitted
fix: preserve service layer state on SDK initialization failure
State is now only reset after Approov.initialize() confirms success. When the SDK throws (e.g. different config), all prior operating state (isInitialized, configString, pinningInterceptor, OkHttp builder) is preserved. Per TESTING_REQUIREMENTS §17-18 (core-service-layers-testing).
1 parent 9c03c1b commit f8b7ddd

2 files changed

Lines changed: 22 additions & 25 deletions

File tree

approov-service/src/main/java/io/approov/service/retrofit/ApproovService.java

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,25 @@ private ApproovService() {
163163
public static synchronized void initialize(Context context, String config, String comment) {
164164
if (config == null)
165165
throw new IllegalArgumentException("config must not be null; pass \"\" for bypass mode");
166-
// Reset service layer state
166+
167+
// Initialize the platform SDK if not in bypass mode (empty config).
168+
// State is only modified after the SDK confirms success, preserving the current
169+
// operating mode (protected or bypass) if the call fails.
170+
if (!config.isEmpty()) {
171+
try {
172+
boolean sdkInitialized = Approov.initialize(context.getApplicationContext(), config, "auto", comment);
173+
if (!sdkInitialized) {
174+
Log.d(TAG, "Approov SDK already initialized");
175+
}
176+
} catch (IllegalArgumentException e) {
177+
Log.e(TAG, "Approov initialization failed: " + e.getMessage());
178+
throw e; // service-layer state NOT modified — prior operating mode preserved
179+
} catch (IllegalStateException e) {
180+
Log.e(TAG, "Approov initialization failed: " + e.getMessage());
181+
throw e; // service-layer state NOT modified — prior operating mode preserved
182+
}
183+
}
184+
// SDK succeeded (or bypass) — now reset and commit new service-layer state.
167185
isInitialized = false;
168186
proceedOnNetworkFail = false;
169187
useApproovStatusIfNoToken = false;
@@ -181,26 +199,6 @@ public static synchronized void initialize(Context context, String config, Strin
181199
cachedFailureResult = null;
182200
cachedFailureTimeMs = 0;
183201
}
184-
185-
// Initialize the platform SDK if not in bypass mode (empty config).
186-
// The SDK returns true if initialization succeeded, false if already
187-
// initialized
188-
// with the same config even by another service layer instance. Any other
189-
// failure (e.g. different config) throws.
190-
if (!config.isEmpty()) {
191-
try {
192-
boolean sdkInitialized = Approov.initialize(context.getApplicationContext(), config, "auto", comment);
193-
if (!sdkInitialized) {
194-
Log.d(TAG, "Approov SDK already initialized");
195-
}
196-
} catch (IllegalArgumentException e) {
197-
Log.e(TAG, "Approov initialization failed: " + e.getMessage());
198-
throw e;
199-
} catch (IllegalStateException e) {
200-
Log.e(TAG, "Approov initialization failed: " + e.getMessage());
201-
throw e;
202-
}
203-
}
204202
if (!config.isEmpty())
205203
pinningInterceptor = new ApproovPinningInterceptor();
206204
else

approov-service/src/test/java/io/approov/service/retrofit/ApproovServiceContractTest.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,10 @@ public void initializeWithEmptyConfigCanLaterBuildProtectedClients() {
8585
}
8686

8787
@Test
88-
public void initializeWithNullConfigAndCommentSucceedsAsBypass() {
88+
public void initializeWithNullConfigThrowsIllegalArgument() {
8989
Context context = mock(Context.class);
90-
ApproovService.initialize(context, null, null);
91-
assertTrue(ApproovService.isInitialized());
92-
assertFalse(ApproovService.isApproovEnabled());
90+
assertThrows(IllegalArgumentException.class, () -> ApproovService.initialize(context, null, null));
91+
assertFalse(ApproovService.isInitialized());
9392
}
9493

9594
@Test

0 commit comments

Comments
 (0)