1 /*
2  * Copyright (C) 2017 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.backup.utils;
18 
19 import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS;
20 import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
21 import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE;
22 import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
23 import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS;
24 
25 import static com.android.server.backup.BackupManagerService.DEBUG;
26 import static com.android.server.backup.BackupManagerService.TAG;
27 
28 import android.annotation.Nullable;
29 import android.app.IBackupAgent;
30 import android.app.backup.BackupAnnotations.OperationType;
31 import android.app.backup.BackupManagerMonitor;
32 import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
33 import android.app.backup.IBackupManagerMonitor;
34 import android.content.pm.PackageInfo;
35 import android.os.Bundle;
36 import android.os.RemoteException;
37 import android.util.Slog;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.internal.infra.AndroidFuture;
41 
42 import java.util.List;
43 import java.util.concurrent.TimeUnit;
44 import java.util.concurrent.TimeoutException;
45 
46 /**
47  * Utility methods to log BackupManagerMonitor events.
48  */
49 public class BackupManagerMonitorEventSender {
50     /**
51      * Timeout for how long we wait before we give up on getting logs from a {@link IBackupAgent}.
52      * We expect this to be very fast since the agent immediately returns whatever logs have been
53      * accumulated. The timeout adds a bit more security and ensures we don't hang the B&R waiting
54      * for non-essential logs.
55      */
56     private static final int AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS = 500;
57     @Nullable private IBackupManagerMonitor mMonitor;
58     private final BackupManagerMonitorDumpsysUtils mBackupManagerMonitorDumpsysUtils;
BackupManagerMonitorEventSender(@ullable IBackupManagerMonitor monitor)59     public BackupManagerMonitorEventSender(@Nullable IBackupManagerMonitor monitor) {
60         mMonitor = monitor;
61         mBackupManagerMonitorDumpsysUtils = new BackupManagerMonitorDumpsysUtils();
62     }
63 
64     @VisibleForTesting
BackupManagerMonitorEventSender(@ullable IBackupManagerMonitor monitor, BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils)65     BackupManagerMonitorEventSender(@Nullable IBackupManagerMonitor monitor,
66             BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils) {
67         mMonitor = monitor;
68         mBackupManagerMonitorDumpsysUtils = backupManagerMonitorDumpsysUtils;
69     }
70 
setMonitor(IBackupManagerMonitor monitor)71     public void setMonitor(IBackupManagerMonitor monitor) {
72         mMonitor = monitor;
73     }
74 
getMonitor()75     public IBackupManagerMonitor getMonitor() {
76         return mMonitor;
77     }
78 
79     /**
80      * Notifies monitor about the event.
81      *
82      * Calls {@link IBackupManagerMonitor#onEvent(Bundle)} with a bundle representing current event.
83      *
84      * @param id - event id.
85      * @param pkg - package event is related to.
86      * @param category - event category.
87      * @param extras - additional event data.
88      */
monitorEvent( int id, PackageInfo pkg, int category, Bundle extras)89     public void monitorEvent(
90             int id,
91             PackageInfo pkg,
92             int category,
93             Bundle extras) {
94         try {
95             Bundle bundle = new Bundle();
96             bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
97             bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category);
98             if (pkg != null) {
99                 bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME,
100                         pkg.packageName);
101                 bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
102                         pkg.versionCode);
103                 bundle.putLong(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION,
104                         pkg.getLongVersionCode());
105             }
106             if (extras != null) {
107                 bundle.putAll(extras);
108                 if (extras.containsKey(EXTRA_LOG_OPERATION_TYPE) &&
109                         extras.getInt(EXTRA_LOG_OPERATION_TYPE) == OperationType.RESTORE){
110                     mBackupManagerMonitorDumpsysUtils
111                             .parseBackupManagerMonitorRestoreEventForDumpsys(bundle);
112                 }
113             }
114 
115             if (mMonitor != null) {
116                 mMonitor.onEvent(bundle);
117             } else {
118                 if (DEBUG) {
119                     Slog.w(TAG, "backup manager monitor is null unable to send event");
120                 }
121             }
122         } catch (RemoteException e) {
123             mMonitor = null;
124             if (DEBUG) {
125                 Slog.w(TAG, "backup manager monitor went away");
126             }
127         }
128     }
129 
130     /**
131      * Extracts logging results from the provided {@code agent} and notifies the {@code monitor}
132      * about them.
133      *
134      * <p>Note that this method does two separate binder calls (one to the agent and one to the
135      * monitor).
136      *
137      * @param pkg - package the {@code agent} belongs to.
138      * @param agent - the {@link IBackupAgent} to retrieve logs from.
139      */
monitorAgentLoggingResults(PackageInfo pkg, IBackupAgent agent)140     public void monitorAgentLoggingResults(PackageInfo pkg, IBackupAgent agent) {
141         if (mMonitor == null) {
142             Slog.i(TAG, "backup manager monitor is null unable to send event"+pkg);
143         }
144 
145         try {
146             AndroidFuture<List<DataTypeResult>> resultsFuture =
147                     new AndroidFuture<>();
148             AndroidFuture<Integer> operationTypeFuture = new AndroidFuture<>();
149             agent.getLoggerResults(resultsFuture);
150             agent.getOperationType(operationTypeFuture);
151             sendAgentLoggingResults(pkg,
152                     resultsFuture.get(AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS),
153                     operationTypeFuture.get(AGENT_LOGGER_RESULTS_TIMEOUT_MILLIS,
154                             TimeUnit.MILLISECONDS));
155         } catch (TimeoutException e) {
156             Slog.w(TAG, "Timeout while waiting to retrieve logging results from agent", e);
157         } catch (Exception e) {
158             Slog.w(TAG, "Failed to retrieve logging results from agent", e);
159         }
160     }
161 
sendAgentLoggingResults(PackageInfo pkg, List<DataTypeResult> results, @OperationType int operationType)162     public void sendAgentLoggingResults(PackageInfo pkg, List<DataTypeResult> results,
163             @OperationType int operationType) {
164         Bundle loggerResultsBundle = new Bundle();
165         loggerResultsBundle.putParcelableList(
166                 EXTRA_LOG_AGENT_LOGGING_RESULTS, results);
167         loggerResultsBundle.putInt(EXTRA_LOG_OPERATION_TYPE, operationType);
168         monitorEvent(
169                 LOG_EVENT_ID_AGENT_LOGGING_RESULTS,
170                 pkg,
171                 LOG_EVENT_CATEGORY_AGENT,
172                 loggerResultsBundle);
173     }
174 
175     /**
176      * Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
177      * be created.
178      *
179      * @param extras - bundle where to add key-value to, if null a new bundle will be created.
180      * @param key - key.
181      * @param value - value.
182      * @return extras if it was not null and new bundle otherwise.
183      */
putMonitoringExtra(Bundle extras, String key, String value)184     public static Bundle putMonitoringExtra(Bundle extras, String key, String value) {
185         if (extras == null) {
186             extras = new Bundle();
187         }
188         extras.putString(key, value);
189         return extras;
190     }
191 
192     /**
193      * Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
194      * be created.
195      *
196      * @param extras - bundle where to add key-value to, if null a new bundle will be created.
197      * @param key - key.
198      * @param value - value.
199      * @return extras if it was not null and new bundle otherwise.
200      */
putMonitoringExtra(Bundle extras, String key, long value)201     public static Bundle putMonitoringExtra(Bundle extras, String key, long value) {
202         if (extras == null) {
203             extras = new Bundle();
204         }
205         extras.putLong(key, value);
206         return extras;
207     }
208 
209     /**
210      * Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
211      * be created.
212      *
213      * @param extras - bundle where to add key-value to, if null a new bundle will be created.
214      * @param key - key.
215      * @param value - value.
216      * @return extras if it was not null and new bundle otherwise.
217      */
putMonitoringExtra(Bundle extras, String key, boolean value)218     public static Bundle putMonitoringExtra(Bundle extras, String key, boolean value) {
219         if (extras == null) {
220             extras = new Bundle();
221         }
222         extras.putBoolean(key, value);
223         return extras;
224     }
225 
226     /**
227      * Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
228      * be created.
229      *
230      * @param extras - bundle where to add key-value to, if null a new bundle will be created.
231      * @param key - key.
232      * @param value - value.
233      * @return extras if it was not null and new bundle otherwise.
234      */
putMonitoringExtra(Bundle extras, String key, int value)235     public static Bundle putMonitoringExtra(Bundle extras, String key, int value) {
236         if (extras == null) {
237             extras = new Bundle();
238         }
239         extras.putInt(key, value);
240         return extras;
241     }
242 }
243