• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.adservices.service.measurement.util;
18 
19 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.AGGREGATE_REPORTING;
20 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.ASYNC_REGISTRATION_PROCESSING;
21 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.ATTRIBUTION_PROCESSING;
22 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.DEBUG_REPORTING;
23 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.EVENT_REPORTING;
24 import static com.android.adservices.service.measurement.util.JobLockHolder.Type.VERBOSE_DEBUG_REPORTING;
25 
26 import android.annotation.Nullable;
27 
28 import com.android.adservices.LoggerFactory;
29 import com.android.adservices.LoggerFactory.Logger;
30 
31 import com.google.common.annotations.VisibleForTesting;
32 
33 import java.util.Map;
34 import java.util.Objects;
35 import java.util.concurrent.locks.ReentrantLock;
36 import java.util.function.Supplier;
37 
38 /**
39  * Holds the lock to be used by the background jobs. The locks will be used by multiple jobs,
40  * fallback jobs, and similar functions that could perform the same action. However, only one of
41  * these functions should be able to process at a time. This is to prevent conflicts and ensure that
42  * the system runs smoothly.
43  */
44 public final class JobLockHolder {
45     public enum Type {
46         AGGREGATE_REPORTING,
47         ASYNC_REGISTRATION_PROCESSING,
48         ATTRIBUTION_PROCESSING,
49         DEBUG_REPORTING,
50         EVENT_REPORTING,
51         VERBOSE_DEBUG_REPORTING
52     }
53 
54     private static final Map<Type, JobLockHolder> INSTANCES =
55             Map.of(
56                     AGGREGATE_REPORTING, new JobLockHolder(AGGREGATE_REPORTING),
57                     ASYNC_REGISTRATION_PROCESSING, new JobLockHolder(ASYNC_REGISTRATION_PROCESSING),
58                     ATTRIBUTION_PROCESSING, new JobLockHolder(ATTRIBUTION_PROCESSING),
59                     DEBUG_REPORTING, new JobLockHolder(DEBUG_REPORTING),
60                     EVENT_REPORTING, new JobLockHolder(EVENT_REPORTING),
61                     VERBOSE_DEBUG_REPORTING, new JobLockHolder(VERBOSE_DEBUG_REPORTING));
62 
63     private final Type mType;
64 
65     /* Holds the lock that will be given per instance */
66     private final ReentrantLock mLock;
67 
JobLockHolder(Type type)68     private JobLockHolder(Type type) {
69         this(type, new ReentrantLock());
70     }
71 
72     @VisibleForTesting
JobLockHolder(Type type, ReentrantLock lock)73     JobLockHolder(Type type, ReentrantLock lock) {
74         mType = type;
75         mLock = lock;
76     }
77 
78     /**
79      * Retrieves an instance that has already been created based on its type.
80      *
81      * @param type of lock to be shared by similar tasks
82      * @return lock instance
83      */
getInstance(Type type)84     public static JobLockHolder getInstance(Type type) {
85         return INSTANCES.get(type);
86     }
87 
88     /**
89      * Runs the given runnable after acquiring the lock.
90      *
91      * @param tag name of the caller (used for logging purposes)
92      * @param runnable what to run
93      */
runWithLock(String tag, Runnable runnable)94     public void runWithLock(String tag, Runnable runnable) {
95         Objects.requireNonNull(tag, "tag cannot be null");
96         Objects.requireNonNull(runnable, "runnable cannot be null");
97 
98         Logger logger = LoggerFactory.getMeasurementLogger();
99         logger.v("%s.runWithLock(%s) started", tag, mType);
100 
101         if (mLock.tryLock()) {
102             try {
103                 runnable.run();
104             } finally {
105                 mLock.unlock();
106             }
107             return;
108         }
109 
110         logger.e("%s.runWithLock(%s) failed to acquire lock", tag, mType);
111     }
112 
113     /**
114      * Calls the given "callable" after acquiring the lock.
115      *
116      * @param tag name of the caller (used for logging purposes)
117      * @param callable what to call (i.e, the value returned by {@code get()}.
118      * @param lockFailureResult what to return if the lock could not be acquired
119      * @return result of callable, or {@code failureResult} if the lock could not be acquired.
120      */
callWithLock(String tag, Supplier<T> callable, @Nullable T lockFailureResult)121     public <T> T callWithLock(String tag, Supplier<T> callable, @Nullable T lockFailureResult) {
122         Objects.requireNonNull(tag, "tag cannot be null");
123         Objects.requireNonNull(callable, "callable cannot be null");
124 
125         Logger logger = LoggerFactory.getMeasurementLogger();
126         logger.v("%s.callWithLock(%s) started", tag, mType);
127 
128         if (mLock.tryLock()) {
129             try {
130                 return callable.get();
131             } finally {
132                 mLock.unlock();
133             }
134         }
135 
136         logger.e(
137                 "%s.callWithLock(%s) failed to acquire lock; returning %s",
138                 tag, mType, lockFailureResult);
139         return lockFailureResult;
140     }
141 
142     @Override
toString()143     public String toString() {
144         return "JobLockHolder[mType=" + mType + ", mLock=" + mLock + "]";
145     }
146 }
147