• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.statementservice.domain.worker
18 
19 import android.content.Context
20 import androidx.work.NetworkType
21 import androidx.work.WorkerParameters
22 import com.android.statementservice.domain.VerifyStatus
23 import com.android.statementservice.utils.AndroidUtils
24 import kotlinx.coroutines.async
25 import kotlinx.coroutines.awaitAll
26 import kotlinx.coroutines.coroutineScope
27 import kotlinx.coroutines.isActive
28 import java.util.UUID
29 
30 /**
31  * Scheduled every 24 hours with [NetworkType.CONNECTED] and every 72 hours without any constraints
32  * to retry all domains for all packages with a failing error code.
33  */
34 class RetryRequestWorker(
35     appContext: Context,
36     params: WorkerParameters
37 ) : BaseRequestWorker(appContext, params) {
38 
39     data class VerifyResult(val domainSetId: UUID, val host: String, val status: VerifyStatus)
40 
41     override suspend fun doWork() = coroutineScope {
42         if (!AndroidUtils.isReceiverV2Enabled(appContext)) {
43             return@coroutineScope Result.success()
44         }
45 
46         val packageNames = verificationManager.queryValidVerificationPackageNames()
47 
48         verifier.collectHosts(packageNames)
49             .map { (domainSetId, packageName, host) ->
50                 async {
51                     if (isActive && !isStopped) {
52                         val (_, status) = verifier.verifyHost(host, packageName, params.network)
53                         VerifyResult(domainSetId, host, status)
54                     } else {
55                         // If the job gets cancelled, stop the remaining hosts, but continue the
56                         // job to commit the results for hosts that were already requested.
57                         null
58                     }
59                 }
60             }
61             .awaitAll()
62             .filterNotNull() // TODO(b/159952358): Fast fail packages which can't be retrieved.
63             .groupBy { it.domainSetId }
64             .forEach { (domainSetId, resultsById) ->
65                 resultsById.groupBy { it.status }
66                     .mapValues { it.value.map(VerifyResult::host).toSet() }
67                     .forEach { (status, hosts) ->
68                         verificationManager.setDomainVerificationStatus(
69                             domainSetId,
70                             hosts,
71                             status.value
72                         )
73                     }
74             }
75 
76         // Succeed regardless of results since this retry is best effort and not required
77         Result.success()
78     }
79 }
80