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.server.sdksandbox;
18 
19 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_LOAD_SDK_ALREADY_LOADED;
20 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_LOAD_SDK_INTERNAL_ERROR;
21 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_LOAD_SDK_NOT_FOUND;
22 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_LOAD_SDK_SDK_DEFINED_ERROR;
23 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_LOAD_SDK_SDK_SANDBOX_DISABLED;
24 import static android.app.sdksandbox.SandboxLatencyInfo.RESULT_CODE_SDK_SANDBOX_PROCESS_NOT_AVAILABLE;
25 
26 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_ALREADY_LOADED;
27 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_INTERNAL_ERROR;
28 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_NOT_FOUND;
29 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_SDK_DEFINED_ERROR;
30 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_SDK_SANDBOX_DISABLED;
31 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__RESULT_CODE_UNSPECIFIED;
32 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_API_CALLED__RESULT_CODE__SDK_SANDBOX_PROCESS_NOT_AVAILABLE;
33 
34 import android.app.sdksandbox.SandboxLatencyInfo;
35 import android.os.Binder;
36 import android.util.Log;
37 
38 import com.android.sdksandbox.service.stats.SdkSandboxStatsLog;
39 
40 /**
41  * Helper class to handle StatsD metrics logging logic.
42  *
43  * @hide
44  */
45 class SdkSandboxStatsdLogger {
46     private static final String TAG = SdkSandboxStatsdLogger.class.getSimpleName();
47 
48     /**
49      * Send sandbox API call latency data to StatsD. Corresponding StatsD atom is SandboxApiCalled.
50      */
logSandboxApiLatency(SandboxLatencyInfo sandboxLatencyInfo)51     public void logSandboxApiLatency(SandboxLatencyInfo sandboxLatencyInfo) {
52         int method = convertToStatsLogMethodCode(sandboxLatencyInfo.getMethod());
53         if (method == SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__METHOD_UNSPECIFIED) {
54             Log.w(TAG, "Not logging sandbox API latency for unspecified method");
55             return;
56         }
57         int resultCode = convertToStatsLogResultCode(sandboxLatencyInfo.getResultCode());
58         int callingUid = Binder.getCallingUid();
59 
60         logSandboxApiLatencyForStage(
61                 method,
62                 sandboxLatencyInfo.getAppToSystemServerLatency(),
63                 sandboxLatencyInfo.isSuccessfulAtAppToSystemServer(),
64                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__APP_TO_SYSTEM_SERVER,
65                 callingUid,
66                 resultCode);
67         logSandboxApiLatencyForStage(
68                 method,
69                 sandboxLatencyInfo.getSystemServerAppToSandboxLatency(),
70                 sandboxLatencyInfo.isSuccessfulAtSystemServerAppToSandbox(),
71                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SYSTEM_SERVER_APP_TO_SANDBOX,
72                 callingUid,
73                 resultCode);
74         logSandboxApiLatencyForStage(
75                 method,
76                 sandboxLatencyInfo.getLoadSandboxLatency(),
77                 sandboxLatencyInfo.isSuccessfulAtLoadSandbox(),
78                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__LOAD_SANDBOX,
79                 callingUid,
80                 resultCode);
81         logSandboxApiLatencyForStage(
82                 method,
83                 sandboxLatencyInfo.getSystemServerToSandboxLatency(),
84                 sandboxLatencyInfo.isSuccessfulAtSystemServerToSandbox(),
85                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SYSTEM_SERVER_TO_SANDBOX,
86                 callingUid,
87                 resultCode);
88         logSandboxApiLatencyForStage(
89                 method,
90                 sandboxLatencyInfo.getSandboxLatency(),
91                 sandboxLatencyInfo.isSuccessfulAtSandbox(),
92                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SANDBOX,
93                 callingUid,
94                 resultCode);
95         logSandboxApiLatencyForStage(
96                 method,
97                 sandboxLatencyInfo.getSdkLatency(),
98                 sandboxLatencyInfo.isSuccessfulAtSdk(),
99                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SDK,
100                 callingUid,
101                 resultCode);
102         logSandboxApiLatencyForStage(
103                 method,
104                 sandboxLatencyInfo.getSandboxToSystemServerLatency(),
105                 sandboxLatencyInfo.isSuccessfulAtSandboxToSystemServer(),
106                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SANDBOX_TO_SYSTEM_SERVER,
107                 callingUid,
108                 resultCode);
109         logSandboxApiLatencyForStage(
110                 method,
111                 sandboxLatencyInfo.getSystemServerSandboxToAppLatency(),
112                 sandboxLatencyInfo.isSuccessfulAtSystemServerSandboxToApp(),
113                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SYSTEM_SERVER_SANDBOX_TO_APP,
114                 callingUid,
115                 resultCode);
116         logSandboxApiLatencyForStage(
117                 method,
118                 sandboxLatencyInfo.getSystemServerToAppLatency(),
119                 sandboxLatencyInfo.isSuccessfulAtSystemServerToApp(),
120                 SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__SYSTEM_SERVER_TO_APP,
121                 callingUid,
122                 resultCode);
123 
124         int totalCallStage = SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__TOTAL;
125         if (method == SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__LOAD_SDK
126                 && sandboxLatencyInfo.getLoadSandboxLatency() != -1) {
127             totalCallStage = SdkSandboxStatsLog.SANDBOX_API_CALLED__STAGE__TOTAL_WITH_LOAD_SANDBOX;
128         }
129         logSandboxApiLatencyForStage(
130                 method,
131                 sandboxLatencyInfo.getTotalCallLatency(),
132                 sandboxLatencyInfo.isTotalCallSuccessful(),
133                 totalCallStage,
134                 callingUid,
135                 resultCode);
136     }
137 
convertToStatsLogMethodCode(int method)138     private int convertToStatsLogMethodCode(int method) {
139         return switch (method) {
140             case SandboxLatencyInfo.METHOD_LOAD_SDK ->
141                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__LOAD_SDK;
142             case SandboxLatencyInfo.METHOD_LOAD_SDK_VIA_CONTROLLER ->
143                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__LOAD_SDK_VIA_CONTROLLER;
144             case SandboxLatencyInfo.METHOD_GET_SANDBOXED_SDKS ->
145                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__GET_SANDBOXED_SDKS;
146             case SandboxLatencyInfo.METHOD_GET_SANDBOXED_SDKS_VIA_CONTROLLER ->
147                     SdkSandboxStatsLog
148                             .SANDBOX_API_CALLED__METHOD__GET_SANDBOXED_SDKS_VIA_CONTROLLER;
149             case SandboxLatencyInfo.METHOD_SYNC_DATA_FROM_CLIENT ->
150                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__SYNC_DATA_FROM_CLIENT;
151             case SandboxLatencyInfo.METHOD_REQUEST_SURFACE_PACKAGE ->
152                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__REQUEST_SURFACE_PACKAGE;
153             case SandboxLatencyInfo.METHOD_REGISTER_APP_OWNED_SDK_SANDBOX_INTERFACE ->
154                     SdkSandboxStatsLog
155                             .SANDBOX_API_CALLED__METHOD__REGISTER_APP_OWNED_SDK_SANDBOX_INTERFACE;
156             case SandboxLatencyInfo.METHOD_UNREGISTER_APP_OWNED_SDK_SANDBOX_INTERFACE ->
157                     SdkSandboxStatsLog
158                             .SANDBOX_API_CALLED__METHOD__UNREGISTER_APP_OWNED_SDK_SANDBOX_INTERFACE;
159             case SandboxLatencyInfo.METHOD_GET_APP_OWNED_SDK_SANDBOX_INTERFACES ->
160                     SdkSandboxStatsLog
161                             .SANDBOX_API_CALLED__METHOD__GET_APP_OWNED_SDK_SANDBOX_INTERFACES;
162             case SandboxLatencyInfo.METHOD_UNLOAD_SDK ->
163                     SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__UNLOAD_SDK;
164             case SandboxLatencyInfo.METHOD_ADD_SDK_SANDBOX_LIFECYCLE_CALLBACK ->
165                     SdkSandboxStatsLog
166                             .SANDBOX_API_CALLED__METHOD__ADD_SDK_SANDBOX_LIFECYCLE_CALLBACK;
167             case SandboxLatencyInfo.METHOD_REMOVE_SDK_SANDBOX_LIFECYCLE_CALLBACK ->
168                     SdkSandboxStatsLog
169                             .SANDBOX_API_CALLED__METHOD__REMOVE_SDK_SANDBOX_LIFECYCLE_CALLBACK;
170             default -> SdkSandboxStatsLog.SANDBOX_API_CALLED__METHOD__METHOD_UNSPECIFIED;
171         };
172     }
173 
convertToStatsLogResultCode(@andboxLatencyInfo.ResultCode int resultCode)174     private int convertToStatsLogResultCode(@SandboxLatencyInfo.ResultCode int resultCode) {
175         return switch (resultCode) {
176             case RESULT_CODE_LOAD_SDK_NOT_FOUND ->
177                     SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_NOT_FOUND;
178             case RESULT_CODE_LOAD_SDK_ALREADY_LOADED ->
179                     SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_ALREADY_LOADED;
180             case RESULT_CODE_LOAD_SDK_SDK_DEFINED_ERROR ->
181                     SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_SDK_DEFINED_ERROR;
182             case RESULT_CODE_LOAD_SDK_SDK_SANDBOX_DISABLED ->
183                     SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_SDK_SANDBOX_DISABLED;
184             case RESULT_CODE_LOAD_SDK_INTERNAL_ERROR ->
185                     SANDBOX_API_CALLED__RESULT_CODE__LOAD_SDK_INTERNAL_ERROR;
186             case RESULT_CODE_SDK_SANDBOX_PROCESS_NOT_AVAILABLE ->
187                     SANDBOX_API_CALLED__RESULT_CODE__SDK_SANDBOX_PROCESS_NOT_AVAILABLE;
188             default -> SANDBOX_API_CALLED__RESULT_CODE__RESULT_CODE_UNSPECIFIED;
189         };
190     }
191 
192     private void logSandboxApiLatencyForStage(
193             int method, int latency, boolean success, int stage, int callingUid, int resultCode) {
194         if (latency != -1) {
195             SdkSandboxStatsLog.write(
196                     SdkSandboxStatsLog.SANDBOX_API_CALLED,
197                     method,
198                     latency,
199                     success,
200                     stage,
201                     callingUid,
202                     resultCode);
203         }
204     }
205 
206     /**
207      * Send sandbox activity API call latency data to StatsD. Corresponding StatsD atom is
208      * SandboxActivityEventOccurred.
209      */
210     public void logSandboxActivityApiLatency(
211             int method, int callResult, int latencyMillis, int clientUid) {
212         SdkSandboxStatsLog.write(
213                 SdkSandboxStatsLog.SANDBOX_ACTIVITY_EVENT_OCCURRED,
214                 method,
215                 callResult,
216                 latencyMillis,
217                 clientUid,
218                 /*sdkUid=*/ -1);
219     }
220 }
221