Skip to content

Commit bbd2004

Browse files
committed
wip
1 parent b412e0d commit bbd2004

File tree

1 file changed

+169
-85
lines changed

1 file changed

+169
-85
lines changed

common/src/main/java/com/microsoft/identity/common/internal/activebrokerdiscovery/BrokerDiscoveryClient.kt

Lines changed: 169 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
112112
*
113113
* @param brokerCandidates the candidate(s) to query from.
114114
* @param ipcStrategy the ipc mechanism to query with.
115-
* @param isPackageInstalled a method which returns true if the provided [BrokerData] is installed.
116-
* @param shouldStopQueryForAWhile a method which, if invoked, will force [BrokerDiscoveryClient]
117-
* to skip the IPC discovery process for a while.
115+
* @param isPackageInstalled a function to determine if any given broker app is installed.
116+
* @param isValidBroker a function to determine if the installed broker app contains a matching signature hash.
118117
**/
119118
internal suspend fun queryFromBroker(
120119
brokerCandidates: Set<BrokerData>,
@@ -206,6 +205,15 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
206205
}
207206
}
208207

208+
data class BrokerInMemoryCache (
209+
val brokerData: BrokerData?
210+
)
211+
212+
// Null = not yet queried.
213+
// Non-null = queried before. (the broker data could either be null (no broker installed) or non-null))
214+
@Volatile
215+
private var cachedBroker: BrokerInMemoryCache? = null
216+
209217
constructor(context: Context,
210218
components: IPlatformComponents,
211219
cache: IClientActiveBrokerCache) : this(
@@ -225,6 +233,7 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
225233
@kotlin.jvm.Throws(ClientException::class)
226234
override fun forceBrokerRediscovery(brokerCandidate: BrokerData): BrokerData {
227235
val methodTag = "$TAG:forceBrokerRediscovery"
236+
228237
return runBlocking {
229238
classLevelLock.withLock {
230239
try {
@@ -256,7 +265,7 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
256265
FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_UNEXPECTED_ERROR,
257266
"Result bundle should not be null."
258267
)
259-
cache.setCachedActiveBroker(result)
268+
cacheActiveBroker(result)
260269
return@runBlocking result
261270
} catch (c: ClientException) {
262271
Logger.error(methodTag, "forceBrokerRediscovery Failed.", c)
@@ -274,112 +283,187 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
274283
}
275284

276285
override fun getActiveBroker(shouldSkipCache: Boolean): BrokerData? {
277-
return runBlocking {
278-
return@runBlocking getActiveBrokerAsync(shouldSkipCache, null)
279-
}
286+
return getActiveBrokerInternal (shouldSkipCache, null)
280287
}
281288

282289
override fun getActiveBroker(
283290
shouldSkipCache: Boolean,
284291
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback
285292
): BrokerData? {
286-
return runBlocking {
287-
return@runBlocking getActiveBrokerAsync(shouldSkipCache, telemetryCallback)
288-
}
293+
return getActiveBrokerInternal (shouldSkipCache, telemetryCallback)
289294
}
290295

291-
private suspend fun getActiveBrokerAsync(shouldSkipCache:Boolean,
292-
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback?): BrokerData?{
293-
val methodTag = "$TAG:getActiveBrokerAsync"
294-
295-
val timeStartAcquiringLock = System.nanoTime()
296-
classLevelLock.withLock {
297-
telemetryCallback?.onLockAcquired(System.nanoTime() - timeStartAcquiringLock)
298-
if (!shouldSkipCache) {
299-
if (cache.shouldUseAccountManager()) {
300-
telemetryCallback?.onUseAccountManager()
301-
return getActiveBrokerFromAccountManager()
302-
}
303-
val timeStartReadingFromCache = System.nanoTime()
304-
cache.getCachedActiveBroker()?.let {
305-
telemetryCallback?.onReadFromCache(System.nanoTime() - timeStartReadingFromCache)
306-
307-
val timeStartIsPackageInstalled = System.nanoTime()
308-
val isPackageInstalled = isPackageInstalled(it)
309-
telemetryCallback?.onFinishCheckingIfPackageIsInstalled(System.nanoTime() - timeStartIsPackageInstalled)
310-
if (!isPackageInstalled) {
311-
Logger.info(
312-
methodTag,
313-
"There is a cached broker: $it, but the app is no longer installed."
314-
)
315-
cache.clearCachedActiveBroker()
316-
return@let
317-
}
296+
private fun getActiveBrokerInternal(shouldSkipCache: Boolean,
297+
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback?): BrokerData? {
298+
if (!shouldSkipCache) {
299+
getActiveBrokerFromInMemoryCache(telemetryCallback)?.let {
300+
return it
301+
}
302+
}
318303

319-
val timeStartIsValidBroker = System.nanoTime()
320-
val isValidBroker = isValidBroker(it)
321-
telemetryCallback?.onFinishCheckingIfValidBroker(System.nanoTime() - timeStartIsValidBroker)
322-
if (!isValidBroker) {
323-
Logger.info(
324-
methodTag,
325-
"Clearing cache as the installed app does not have a matching signature hash."
326-
)
327-
cache.clearCachedActiveBroker()
328-
return@let
304+
val totalTimeSpentAcquiringLock = System.nanoTime()
305+
return runBlocking {
306+
classLevelLock.withLock {
307+
telemetryCallback?.onLockAcquired(System.nanoTime() - totalTimeSpentAcquiringLock)
308+
309+
if (!shouldSkipCache) {
310+
// Early return if another coroutine has already populated the in-memory cache.
311+
getActiveBrokerFromInMemoryCache(telemetryCallback)?.let {
312+
return@runBlocking it
329313
}
330314

331-
val timeStartIsSupportedByTargetedBroker = System.nanoTime()
332-
val isSupportedByTargetedBroker =
333-
ipcStrategy.isSupportedByTargetedBroker(it.packageName)
334-
telemetryCallback?.onFinishCheckingIfSupportedByTargetedBroker(System.nanoTime() - timeStartIsSupportedByTargetedBroker)
335-
if(!isSupportedByTargetedBroker){
336-
Logger.info(
337-
methodTag,
338-
"Clearing cache as the installed app does not provide any IPC mechanism to communicate to. (e.g. the broker code isn't shipped with this apk)"
339-
)
340-
cache.clearCachedActiveBroker()
341-
return@let
315+
getActiveBrokerFromStorageCache(telemetryCallback)?.let {
316+
return@runBlocking it
342317
}
318+
}
343319

344-
Logger.info(methodTag, "Returning cached broker: $it")
345-
return it
320+
getActiveBrokerFromBrokerApp(telemetryCallback)?.let {
321+
return@runBlocking it
346322
}
323+
324+
return@runBlocking getActiveBrokerFromAccountManager()
347325
}
326+
}
327+
}
348328

349-
val timeStartQueryFromBroker = System.nanoTime()
350-
val brokerData = queryFromBroker(
351-
brokerCandidates = brokerCandidates,
352-
ipcStrategy = ipcStrategy,
353-
isPackageInstalled = isPackageInstalled,
354-
isValidBroker = isValidBroker
355-
)
356-
telemetryCallback?.onFinishQueryingResultFromBroker(System.nanoTime() - timeStartQueryFromBroker)
329+
private fun getActiveBrokerFromInMemoryCache(
330+
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback?
331+
): BrokerData? {
332+
val methodTag = "$TAG:getValidBrokerFromInMemoryCache"
333+
334+
// There's no readWriteLock in coroutines library yet... volatile should be sufficient for our use case here.
335+
cachedBroker?.let {
336+
if (it.brokerData == null){
337+
// "null" value is cached, meaning no valid broker installed.
338+
Logger.info(
339+
methodTag,
340+
"[Cached] No broker app is installed."
341+
)
342+
return null
343+
}
357344

358-
if (brokerData != null) {
359-
cache.setCachedActiveBroker(brokerData)
360-
return brokerData
345+
val timeStartIsValidBroker = System.nanoTime()
346+
val isValidBroker = isValidBroker(it.brokerData)
347+
telemetryCallback?.onFinishCheckingIfValidBroker(System.nanoTime() - timeStartIsValidBroker)
348+
if (isValidBroker) {
349+
return it.brokerData
361350
}
362351

363352
Logger.info(
364353
methodTag,
365-
"Will skip broker discovery via IPC and fall back to AccountManager " +
366-
"for the next 60 minutes."
354+
"Clearing cache as the installed app does not have a matching signature hash."
367355
)
368-
cache.clearCachedActiveBroker()
369-
cache.setShouldUseAccountManagerForTheNextMilliseconds(
370-
TimeUnit.MINUTES.toMillis(
371-
60
356+
clearCachedData()
357+
}
358+
359+
// Nothing valid to return.
360+
return null
361+
}
362+
363+
private fun clearCachedData() {
364+
cachedBroker = null
365+
cache.clearCachedActiveBroker()
366+
}
367+
368+
private fun cacheActiveBroker(brokerData: BrokerData) {
369+
cachedBroker = BrokerInMemoryCache(brokerData)
370+
cache.setCachedActiveBroker(brokerData)
371+
}
372+
373+
private fun getActiveBrokerFromStorageCache(
374+
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback?
375+
): BrokerData? {
376+
val methodTag = "$TAG:getValidBrokerFromInMemoryCache"
377+
val timeStartReadingFromCache = System.nanoTime()
378+
cache.getCachedActiveBroker()?.let {
379+
telemetryCallback?.onReadFromCache(System.nanoTime() - timeStartReadingFromCache)
380+
if (cache.shouldUseAccountManager()) {
381+
telemetryCallback?.onUseAccountManager()
382+
val accountManagerBroker = getActiveBrokerFromAccountManager()
383+
384+
// Only cache in memory, but don't persist accountManager result to cache storage.
385+
cachedBroker = BrokerInMemoryCache(accountManagerBroker)
386+
return accountManagerBroker
387+
}
388+
389+
val timeStartIsPackageInstalled = System.nanoTime()
390+
val isPackageInstalled = isPackageInstalled(it)
391+
telemetryCallback?.onFinishCheckingIfPackageIsInstalled(System.nanoTime() - timeStartIsPackageInstalled)
392+
if (!isPackageInstalled) {
393+
Logger.info(
394+
methodTag,
395+
"There is a cached broker: $it, but the app is no longer installed."
372396
)
373-
)
397+
clearCachedData()
398+
return@let
399+
}
374400

375-
telemetryCallback?.onUseAccountManager()
376-
val accountManagerResult = getActiveBrokerFromAccountManager()
377-
Logger.info(
378-
methodTag, "Tried getting active broker from account manager, " +
379-
"get ${accountManagerResult?.packageName}."
380-
)
401+
val timeStartIsValidBroker = System.nanoTime()
402+
val isValidBroker = isValidBroker(it)
403+
telemetryCallback?.onFinishCheckingIfValidBroker(System.nanoTime() - timeStartIsValidBroker)
404+
if (!isValidBroker) {
405+
Logger.info(
406+
methodTag,
407+
"Clearing cache as the installed app does not have a matching signature hash."
408+
)
409+
clearCachedData()
410+
return@let
411+
}
381412

382-
return accountManagerResult
413+
val timeStartIsSupportedByTargetedBroker = System.nanoTime()
414+
val isSupportedByTargetedBroker =
415+
ipcStrategy.isSupportedByTargetedBroker(it.packageName)
416+
telemetryCallback?.onFinishCheckingIfSupportedByTargetedBroker(System.nanoTime() - timeStartIsSupportedByTargetedBroker)
417+
if(!isSupportedByTargetedBroker){
418+
Logger.info(
419+
methodTag,
420+
"Clearing cache as the installed app does not provide any IPC mechanism to communicate to. (e.g. the broker code isn't shipped with this apk)"
421+
)
422+
clearCachedData()
423+
return@let
424+
}
425+
426+
Logger.info(methodTag, "Returning cached broker: $it")
427+
cacheActiveBroker(it)
428+
return it
383429
}
430+
431+
return null
432+
}
433+
434+
private suspend fun getActiveBrokerFromBrokerApp(
435+
telemetryCallback: IBrokerDiscoveryClientTelemetryCallback?
436+
): BrokerData? {
437+
val methodTag = "$TAG:getActiveBrokerFromBrokerApp"
438+
val timeStartQueryFromBroker = System.nanoTime()
439+
val brokerData = queryFromBroker(
440+
brokerCandidates = brokerCandidates,
441+
ipcStrategy = ipcStrategy,
442+
isPackageInstalled = isPackageInstalled,
443+
isValidBroker = isValidBroker
444+
)
445+
telemetryCallback?.onFinishQueryingResultFromBroker(System.nanoTime() - timeStartQueryFromBroker)
446+
447+
if (brokerData != null) {
448+
cacheActiveBroker(brokerData)
449+
return brokerData
450+
}
451+
452+
cache.setShouldUseAccountManagerForTheNextMilliseconds(
453+
TimeUnit.MINUTES.toMillis(
454+
60
455+
)
456+
)
457+
458+
telemetryCallback?.onUseAccountManager()
459+
val accountManagerResult = getActiveBrokerFromAccountManager()
460+
Logger.info(
461+
methodTag, "Tried getting active broker from account manager, " +
462+
"get ${accountManagerResult?.packageName}."
463+
)
464+
465+
// Only cache in memory, but don't persist accountManager result to cache storage.
466+
cachedBroker = BrokerInMemoryCache(accountManagerResult)
467+
return accountManagerResult
384468
}
385469
}

0 commit comments

Comments
 (0)