1 /* 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 17 package android.content; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.res.AssetFileDescriptor; 22 import android.database.Cursor; 23 import android.database.DatabaseUtils; 24 import android.net.Uri; 25 import android.os.Binder; 26 import android.os.Bundle; 27 import android.os.CancellationSignal; 28 import android.os.ParcelFileDescriptor; 29 import android.os.RemoteException; 30 import android.util.Log; 31 32 import java.io.FileNotFoundException; 33 import java.util.ArrayList; 34 import 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 */ 42 public class LoggingContentInterface implements ContentInterface { 43 private final String tag; 44 private final ContentInterface delegate; 45 LoggingContentInterface(String tag, ContentInterface delegate)46 public LoggingContentInterface(String tag, ContentInterface delegate) { 47 this.tag = tag; 48 this.delegate = delegate; 49 } 50 51 private class Logger implements AutoCloseable { 52 private final StringBuilder sb = new StringBuilder(); 53 Logger(String method, Object... args)54 public Logger(String method, Object... args) { 55 // First, force-unparcel any bundles so we can log them 56 for (Object arg : args) { 57 if (arg instanceof Bundle) { 58 ((Bundle) arg).size(); 59 } 60 } 61 62 sb.append("callingUid=").append(Binder.getCallingUid()).append(' '); 63 sb.append(method); 64 sb.append('(').append(deepToString(args)).append(')'); 65 } 66 deepToString(Object value)67 private String deepToString(Object value) { 68 if (value != null && value.getClass().isArray()) { 69 return Arrays.deepToString((Object[]) value); 70 } else { 71 return String.valueOf(value); 72 } 73 } 74 setResult(T res)75 public <T> T setResult(T res) { 76 if (res instanceof Cursor) { 77 sb.append('\n'); 78 DatabaseUtils.dumpCursor((Cursor) res, sb); 79 } else { 80 sb.append(" = ").append(deepToString(res)); 81 } 82 return res; 83 } 84 85 @Override close()86 public void close() { 87 Log.v(tag, sb.toString()); 88 } 89 } 90 91 @Override query(@onNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)92 public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, 93 @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) 94 throws RemoteException { 95 try (Logger l = new Logger("query", uri, projection, queryArgs, cancellationSignal)) { 96 try { 97 return l.setResult(delegate.query(uri, projection, queryArgs, cancellationSignal)); 98 } catch (Exception res) { 99 l.setResult(res); 100 throw res; 101 } 102 } 103 } 104 105 @Override getType(@onNull Uri uri)106 public @Nullable String getType(@NonNull Uri uri) throws RemoteException { 107 try (Logger l = new Logger("getType", uri)) { 108 try { 109 return l.setResult(delegate.getType(uri)); 110 } catch (Exception res) { 111 l.setResult(res); 112 throw res; 113 } 114 } 115 } 116 117 @Override getStreamTypes(@onNull Uri uri, @NonNull String mimeTypeFilter)118 public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) 119 throws RemoteException { 120 try (Logger l = new Logger("getStreamTypes", uri, mimeTypeFilter)) { 121 try { 122 return l.setResult(delegate.getStreamTypes(uri, mimeTypeFilter)); 123 } catch (Exception res) { 124 l.setResult(res); 125 throw res; 126 } 127 } 128 } 129 130 @Override canonicalize(@onNull Uri uri)131 public @Nullable Uri canonicalize(@NonNull Uri uri) throws RemoteException { 132 try (Logger l = new Logger("canonicalize", uri)) { 133 try { 134 return l.setResult(delegate.canonicalize(uri)); 135 } catch (Exception res) { 136 l.setResult(res); 137 throw res; 138 } 139 } 140 } 141 142 @Override uncanonicalize(@onNull Uri uri)143 public @Nullable Uri uncanonicalize(@NonNull Uri uri) throws RemoteException { 144 try (Logger l = new Logger("uncanonicalize", uri)) { 145 try { 146 return l.setResult(delegate.uncanonicalize(uri)); 147 } catch (Exception res) { 148 l.setResult(res); 149 throw res; 150 } 151 } 152 } 153 154 @Override refresh(@onNull Uri uri, @Nullable Bundle args, @Nullable CancellationSignal cancellationSignal)155 public boolean refresh(@NonNull Uri uri, @Nullable Bundle args, 156 @Nullable CancellationSignal cancellationSignal) throws RemoteException { 157 try (Logger l = new Logger("refresh", uri, args, cancellationSignal)) { 158 try { 159 return l.setResult(delegate.refresh(uri, args, cancellationSignal)); 160 } catch (Exception res) { 161 l.setResult(res); 162 throw res; 163 } 164 } 165 } 166 167 @Override checkUriPermission(@onNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)168 public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) 169 throws RemoteException { 170 try (Logger l = new Logger("checkUriPermission", uri, uid, modeFlags)) { 171 try { 172 return l.setResult(delegate.checkUriPermission(uri, uid, modeFlags)); 173 } catch (Exception res) { 174 l.setResult(res); 175 throw res; 176 } 177 } 178 } 179 180 @Override insert(@onNull Uri uri, @Nullable ContentValues initialValues, @Nullable Bundle extras)181 public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues, 182 @Nullable Bundle extras) throws RemoteException { 183 try (Logger l = new Logger("insert", uri, initialValues, extras)) { 184 try { 185 return l.setResult(delegate.insert(uri, initialValues, extras)); 186 } catch (Exception res) { 187 l.setResult(res); 188 throw res; 189 } 190 } 191 } 192 193 @Override bulkInsert(@onNull Uri uri, @NonNull ContentValues[] initialValues)194 public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] initialValues) 195 throws RemoteException { 196 try (Logger l = new Logger("bulkInsert", uri, initialValues)) { 197 try { 198 return l.setResult(delegate.bulkInsert(uri, initialValues)); 199 } catch (Exception res) { 200 l.setResult(res); 201 throw res; 202 } 203 } 204 } 205 206 @Override delete(@onNull Uri uri, @Nullable Bundle extras)207 public int delete(@NonNull Uri uri, @Nullable Bundle extras) throws RemoteException { 208 try (Logger l = new Logger("delete", uri, extras)) { 209 try { 210 return l.setResult(delegate.delete(uri, extras)); 211 } catch (Exception res) { 212 l.setResult(res); 213 throw res; 214 } 215 } 216 } 217 218 @Override update(@onNull Uri uri, @Nullable ContentValues values, @Nullable Bundle extras)219 public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable Bundle extras) 220 throws RemoteException { 221 try (Logger l = new Logger("update", uri, values, extras)) { 222 try { 223 return l.setResult(delegate.update(uri, values, extras)); 224 } catch (Exception res) { 225 l.setResult(res); 226 throw res; 227 } 228 } 229 } 230 231 @Override openFile(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal signal)232 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode, 233 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 234 try (Logger l = new Logger("openFile", uri, mode, signal)) { 235 try { 236 return l.setResult(delegate.openFile(uri, mode, signal)); 237 } catch (Exception res) { 238 l.setResult(res); 239 throw res; 240 } 241 } 242 } 243 244 @Override openAssetFile(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal signal)245 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode, 246 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 247 try (Logger l = new Logger("openAssetFile", uri, mode, signal)) { 248 try { 249 return l.setResult(delegate.openAssetFile(uri, mode, signal)); 250 } catch (Exception res) { 251 l.setResult(res); 252 throw res; 253 } 254 } 255 } 256 257 @Override openTypedAssetFile(@onNull Uri uri, @NonNull String mimeTypeFilter, @Nullable Bundle opts, @Nullable CancellationSignal signal)258 public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri, 259 @NonNull String mimeTypeFilter, @Nullable Bundle opts, 260 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 261 try (Logger l = new Logger("openTypedAssetFile", uri, mimeTypeFilter, opts, signal)) { 262 try { 263 return l.setResult(delegate.openTypedAssetFile(uri, mimeTypeFilter, opts, signal)); 264 } catch (Exception res) { 265 l.setResult(res); 266 throw res; 267 } 268 } 269 } 270 271 @Override applyBatch(@onNull String authority, @NonNull ArrayList<ContentProviderOperation> operations)272 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority, 273 @NonNull ArrayList<ContentProviderOperation> operations) 274 throws RemoteException, OperationApplicationException { 275 try (Logger l = new Logger("applyBatch", authority, operations)) { 276 try { 277 return l.setResult(delegate.applyBatch(authority, operations)); 278 } catch (Exception res) { 279 l.setResult(res); 280 throw res; 281 } 282 } 283 } 284 285 @Override call(@onNull String authority, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)286 public @Nullable Bundle call(@NonNull String authority, @NonNull String method, 287 @Nullable String arg, @Nullable Bundle extras) throws RemoteException { 288 try (Logger l = new Logger("call", authority, method, arg, extras)) { 289 try { 290 return l.setResult(delegate.call(authority, method, arg, extras)); 291 } catch (Exception res) { 292 l.setResult(res); 293 throw res; 294 } 295 } 296 } 297 } 298