blob: 26d01b99abd0dfb3443bcd3a18087cb3c9efcd47 [file] [log] [blame]
Jeff Sharkeybffd2502019-02-28 16:39:12 -07001/*
2 * Copyright (C) 2019 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
17package android.content;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.content.res.AssetFileDescriptor;
22import android.database.Cursor;
23import android.database.DatabaseUtils;
24import android.net.Uri;
25import android.os.Binder;
26import android.os.Bundle;
27import android.os.CancellationSignal;
28import android.os.ParcelFileDescriptor;
29import android.os.RemoteException;
30import android.util.Log;
31
32import java.io.FileNotFoundException;
33import java.util.ArrayList;
34import java.util.Arrays;
35
36/**
37 * Instance of {@link ContentInterface} that logs all inputs and outputs while
38 * delegating to another {@link ContentInterface}.
39 *
40 * @hide
41 */
42public class LoggingContentInterface implements ContentInterface {
43 private final String tag;
44 private final ContentInterface delegate;
45
46 public LoggingContentInterface(String tag, ContentInterface delegate) {
47 this.tag = tag;
48 this.delegate = delegate;
49 }
50
51 private void log(String method, Object res, Object... args) {
52 // First, force-unparcel any bundles so we can log them
53 for (Object arg : args) {
54 if (arg instanceof Bundle) {
55 ((Bundle) arg).size();
56 }
57 }
58
59 final StringBuilder sb = new StringBuilder();
60 sb.append("callingUid=").append(Binder.getCallingUid()).append(' ');
61 sb.append(method);
62 sb.append('(').append(deepToString(args)).append(')');
63 if (res instanceof Cursor) {
64 sb.append('\n');
65 DatabaseUtils.dumpCursor((Cursor) res, sb);
66 } else {
67 sb.append(" = ").append(deepToString(res));
68 }
69 Log.v(tag, sb.toString());
70 }
71
72 private String deepToString(Object value) {
73 if (value != null && value.getClass().isArray()) {
74 return Arrays.deepToString((Object[]) value);
75 } else {
76 return String.valueOf(value);
77 }
78 }
79
80 @Override
81 public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
82 @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
83 throws RemoteException {
84 final Cursor res = delegate.query(uri, projection, queryArgs, cancellationSignal);
85 log("query", res, uri, projection, queryArgs, cancellationSignal);
86 return res;
87 }
88
89 @Override
90 public @Nullable String getType(@NonNull Uri uri) throws RemoteException {
91 final String res = delegate.getType(uri);
92 log("getType", res, uri);
93 return res;
94 }
95
96 @Override
97 public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter)
98 throws RemoteException {
99 final String[] res = delegate.getStreamTypes(uri, mimeTypeFilter);
100 log("getStreamTypes", res, uri, mimeTypeFilter);
101 return res;
102 }
103
104 @Override
105 public @Nullable Uri canonicalize(@NonNull Uri uri) throws RemoteException {
106 final Uri res = delegate.canonicalize(uri);
107 log("canonicalize", res, uri);
108 return res;
109 }
110
111 @Override
112 public @Nullable Uri uncanonicalize(@NonNull Uri uri) throws RemoteException {
113 final Uri res = delegate.uncanonicalize(uri);
114 log("uncanonicalize", res, uri);
115 return res;
116 }
117
118 @Override
119 public boolean refresh(@NonNull Uri uri, @Nullable Bundle args,
120 @Nullable CancellationSignal cancellationSignal) throws RemoteException {
121 final boolean res = delegate.refresh(uri, args, cancellationSignal);
122 log("refresh", res, uri, args, cancellationSignal);
123 return res;
124 }
125
126 @Override
127 public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
128 throws RemoteException {
129 final Uri res = delegate.insert(uri, initialValues);
130 log("insert", res, uri, initialValues);
131 return res;
132 }
133
134 @Override
135 public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] initialValues)
136 throws RemoteException {
137 final int res = delegate.bulkInsert(uri, initialValues);
138 log("bulkInsert", res, uri, initialValues);
139 return res;
140 }
141
142 @Override
143 public int delete(@NonNull Uri uri, @Nullable String selection,
144 @Nullable String[] selectionArgs) throws RemoteException {
145 final int res = delegate.delete(uri, selection, selectionArgs);
146 log("delete", res, uri, selection, selectionArgs);
147 return res;
148 }
149
150 @Override
151 public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
152 @Nullable String[] selectionArgs) throws RemoteException {
153 final int res = delegate.update(uri, values, selection, selectionArgs);
154 log("update", res, uri, values, selection, selectionArgs);
155 return res;
156 }
157
158 @Override
159 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
160 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
161 final ParcelFileDescriptor res = delegate.openFile(uri, mode, signal);
162 log("openFile", res, uri, mode, signal);
163 return res;
164 }
165
166 @Override
167 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
168 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
169 final AssetFileDescriptor res = delegate.openAssetFile(uri, mode, signal);
170 log("openAssetFile", res, uri, mode, signal);
171 return res;
172 }
173
174 @Override
175 public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
176 @NonNull String mimeTypeFilter, @Nullable Bundle opts,
177 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
178 final AssetFileDescriptor res = delegate.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
179 log("openTypedAssetFile", res, uri, mimeTypeFilter, opts, signal);
180 return res;
181 }
182
183 @Override
184 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
185 @NonNull ArrayList<ContentProviderOperation> operations)
186 throws RemoteException, OperationApplicationException {
187 final ContentProviderResult[] res = delegate.applyBatch(authority, operations);
188 log("applyBatch", res, authority, operations);
189 return res;
190 }
191
192 @Override
193 public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
194 @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
195 final Bundle res = delegate.call(authority, method, arg, extras);
196 log("call", res, authority, method, arg, extras);
197 return res;
198 }
199}