1 /*
2  * Copyright (C) 2024 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.shared.spe.logging;
18 
19 import static com.android.adservices.shared.spe.JobServiceConstants.MAX_PERCENTAGE;
20 import static com.android.adservices.shared.spe.JobServiceConstants.SCHEDULER_TYPE_JOB_SCHEDULER;
21 import static com.android.adservices.shared.spe.JobServiceConstants.SCHEDULER_TYPE_SPE;
22 import static com.android.adservices.shared.spe.JobServiceConstants.SCHEDULING_LOGGING_UNKNOWN_MODULE_NAME;
23 import static com.android.adservices.shared.util.LogUtil.VERBOSE;
24 
25 import android.annotation.NonNull;
26 
27 import com.android.adservices.shared.common.flags.ModuleSharedFlags;
28 import com.android.adservices.shared.spe.JobServiceConstants.JobSchedulingResultCode;
29 import com.android.adservices.shared.util.LogUtil;
30 import com.android.internal.annotations.VisibleForTesting;
31 
32 import java.util.Objects;
33 import java.util.Random;
34 import java.util.concurrent.Executor;
35 
36 /** Class for job scheduling logging methods. */
37 public final class JobSchedulingLogger {
38     private static final Random sRandom = new Random();
39     private final StatsdJobServiceLogger mStatsdLogger;
40     private final Executor mLoggingExecutor;
41     private final ModuleSharedFlags mFlags;
42 
43     /** Creates an instance of {@link JobSchedulingLogger}. */
JobSchedulingLogger( @onNull StatsdJobServiceLogger statsdLogger, @NonNull Executor loggingExecutor, @NonNull ModuleSharedFlags flags)44     public JobSchedulingLogger(
45             @NonNull StatsdJobServiceLogger statsdLogger,
46             @NonNull Executor loggingExecutor,
47             @NonNull ModuleSharedFlags flags) {
48         mStatsdLogger = Objects.requireNonNull(statsdLogger);
49         mLoggingExecutor = Objects.requireNonNull(loggingExecutor);
50         mFlags = Objects.requireNonNull(flags);
51     }
52 
53     /**
54      * Records the result of the scheduling event using SPE (Scheduling Policy Engine).
55      *
56      * @param jobId the job ID of the job to schedule.
57      * @param resultCode the result code of current scheduling event.
58      */
recordOnScheduling(int jobId, @JobSchedulingResultCode int resultCode)59     public void recordOnScheduling(int jobId, @JobSchedulingResultCode int resultCode) {
60         if (!mFlags.getJobSchedulingLoggingEnabled()) {
61             return;
62         }
63 
64         mLoggingExecutor.execute(
65                 () -> logSchedulingStatsHelper(jobId, resultCode, SCHEDULER_TYPE_SPE));
66     }
67 
68     /**
69      * Records the result of the scheduling event using JobScheduler.
70      *
71      * @param jobId the job ID of the job to schedule.
72      * @param resultCode the result code of current scheduling event.
73      */
74     // TODO(b/325292968): remove this once all jobs are migrated to using SPE.
recordOnSchedulingLegacy(int jobId, @JobSchedulingResultCode int resultCode)75     public void recordOnSchedulingLegacy(int jobId, @JobSchedulingResultCode int resultCode) {
76         if (!mFlags.getJobSchedulingLoggingEnabled()) {
77             return;
78         }
79 
80         mLoggingExecutor.execute(
81                 () -> logSchedulingStatsHelper(jobId, resultCode, SCHEDULER_TYPE_JOB_SCHEDULER));
82     }
83 
84     /**
85      * Logs the stats to the logging server.
86      *
87      * @param jobId the job ID of the job to schedule.
88      * @param resultCode the result code of current scheduling event.
89      * @param schedulerType the type of the scheduler used for current scheduling event.
90      */
91     @VisibleForTesting
logSchedulingStatsHelper( int jobId, @JobSchedulingResultCode int resultCode, int schedulerType)92     void logSchedulingStatsHelper(
93             int jobId, @JobSchedulingResultCode int resultCode, int schedulerType) {
94         if (!shouldLog()) {
95             if (VERBOSE) {
96                 LogUtil.v("Job scheduling logging isn't selected for sampling logging, skip...");
97             }
98 
99             return;
100         }
101 
102         SchedulingReportedStats stats =
103                 SchedulingReportedStats.builder()
104                         .setJobId(jobId)
105                         .setResultCode(resultCode)
106                         .setSchedulerType(schedulerType)
107                         .setModuleName(SCHEDULING_LOGGING_UNKNOWN_MODULE_NAME)
108                         .build();
109 
110         mStatsdLogger.logSchedulingReportedStats(stats);
111 
112         if (VERBOSE) {
113             LogUtil.v(
114                     "[Background job scheduling logging] jobId: %d, resultCode: %d, schedulerType:"
115                             + " %d, moduleName:%d",
116                     jobId, resultCode, schedulerType, SCHEDULING_LOGGING_UNKNOWN_MODULE_NAME);
117         }
118     }
119 
120     // Make a random draw to determine if a logging event should be uploaded to the logging server.
121     @VisibleForTesting
shouldLog()122     boolean shouldLog() {
123         int loggingRatio = mFlags.getJobSchedulingLoggingSamplingRate();
124 
125         return sRandom.nextInt(MAX_PERCENTAGE) < loggingRatio;
126     }
127 }
128