1952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor/* 2952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Copyright (C) 2009 The Android Open Source Project 3952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 4952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Licensed under the Apache License, Version 2.0 (the "License"); 5952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * you may not use this file except in compliance with the License. 6952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * You may obtain a copy of the License at 7952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 8952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * http://www.apache.org/licenses/LICENSE-2.0 9952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 10952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Unless required by applicable law or agreed to in writing, software 11952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * distributed under the License is distributed on an "AS IS" BASIS, 12952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * See the License for the specific language governing permissions and 14952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * limitations under the License. 15952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 16952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 17952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorpackage android.os; 18952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 19b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkeyimport android.content.Context; 20b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkeyimport android.util.Log; 21b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey 22f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnorimport com.android.internal.os.IDropBoxManagerService; 23952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 24952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorimport java.io.ByteArrayInputStream; 25cc792c4149b7e768fd894c9b268d815a90a60bd0Brad Fitzpatrickimport java.io.Closeable; 26952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorimport java.io.File; 27952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorimport java.io.IOException; 28952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorimport java.io.InputStream; 29952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnorimport java.util.zip.GZIPInputStream; 30952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 31952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor/** 32952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Enqueues chunks of data (from various sources -- application crashes, kernel 33952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * log records, etc.). The queue is size bounded and will drop old data if the 34952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * enqueued data exceeds the maximum size. You can think of this as a 35952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * persistent, system-wide, blob-oriented "logcat". 36952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 37952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * <p>You can obtain an instance of this class by calling 38952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * {@link android.content.Context#getSystemService} 39952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * with {@link android.content.Context#DROPBOX_SERVICE}. 40952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 41f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnor * <p>DropBoxManager entries are not sent anywhere directly, but other system 42f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnor * services and debugging tools may scan and upload entries for processing. 43952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 44f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnorpublic class DropBoxManager { 45f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnor private static final String TAG = "DropBoxManager"; 46b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey 47b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey private final Context mContext; 48f18a01c77e78209b74e34d05cfb352fa4a92db5fDan Egnor private final IDropBoxManagerService mService; 49952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 50952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** Flag value: Entry's content was deleted to save space. */ 51952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public static final int IS_EMPTY = 1; 52952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 53952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */ 54952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public static final int IS_TEXT = 2; 55952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 56e3cfe2d92868513c9524804a362c3c3c8b8cc4e5Dan Egnor /** Flag value: Content can be decompressed with {@link java.util.zip.GZIPOutputStream}. */ 57952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public static final int IS_GZIPPED = 4; 58952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 596e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor /** Flag value for serialization only: Value is a byte array, not a file descriptor */ 606e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor private static final int HAS_BYTE_ARRAY = 8; 616e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor 62952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 63b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * Broadcast Action: This is broadcast when a new entry is added in the dropbox. 64b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * You must hold the {@link android.Manifest.permission#READ_LOGS} permission 65b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * in order to receive this broadcast. 66b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * 67b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * <p class="note">This is a protected intent that can only be sent 68b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * by the system. 69b247536aa3d458750edbc6b45b2348a994d83426Hakan Still */ 70b247536aa3d458750edbc6b45b2348a994d83426Hakan Still public static final String ACTION_DROPBOX_ENTRY_ADDED = 71b247536aa3d458750edbc6b45b2348a994d83426Hakan Still "android.intent.action.DROPBOX_ENTRY_ADDED"; 72b247536aa3d458750edbc6b45b2348a994d83426Hakan Still 73b247536aa3d458750edbc6b45b2348a994d83426Hakan Still /** 74b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: 75b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * string containing the dropbox tag. 76b247536aa3d458750edbc6b45b2348a994d83426Hakan Still */ 77b247536aa3d458750edbc6b45b2348a994d83426Hakan Still public static final String EXTRA_TAG = "tag"; 78b247536aa3d458750edbc6b45b2348a994d83426Hakan Still 79b247536aa3d458750edbc6b45b2348a994d83426Hakan Still /** 80b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: 81b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * long integer value containing time (in milliseconds since January 1, 1970 00:00:00 UTC) 82b247536aa3d458750edbc6b45b2348a994d83426Hakan Still * when the entry was created. 83b247536aa3d458750edbc6b45b2348a994d83426Hakan Still */ 84b247536aa3d458750edbc6b45b2348a994d83426Hakan Still public static final String EXTRA_TIME = "time"; 85b247536aa3d458750edbc6b45b2348a994d83426Hakan Still 86b247536aa3d458750edbc6b45b2348a994d83426Hakan Still /** 87952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * A single entry retrieved from the drop box. 88952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * This may include a reference to a stream, so you must call 89952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * {@link #close()} when you are done using it. 90952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 91cc792c4149b7e768fd894c9b268d815a90a60bd0Brad Fitzpatrick public static class Entry implements Parcelable, Closeable { 92952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor private final String mTag; 93952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor private final long mTimeMillis; 94952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 95952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor private final byte[] mData; 96952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor private final ParcelFileDescriptor mFileDescriptor; 97952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor private final int mFlags; 98952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 99952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** Create a new empty Entry with no contents. */ 100952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry(String tag, long millis) { 1016e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (tag == null) throw new NullPointerException("tag == null"); 1026e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor 1036e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTag = tag; 1046e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTimeMillis = millis; 1056e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mData = null; 1066e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor = null; 1076e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFlags = IS_EMPTY; 108952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 109952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 110952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** Create a new Entry with plain text contents. */ 111952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry(String tag, long millis, String text) { 1126e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (tag == null) throw new NullPointerException("tag == null"); 1136e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (text == null) throw new NullPointerException("text == null"); 1146e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor 1156e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTag = tag; 1166e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTimeMillis = millis; 1176e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mData = text.getBytes(); 1186e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor = null; 1196e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFlags = IS_TEXT; 120952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 121952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 122952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 123952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Create a new Entry with byte array contents. 124952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * The data array must not be modified after creating this entry. 125952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 126952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry(String tag, long millis, byte[] data, int flags) { 1276e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (tag == null) throw new NullPointerException("tag == null"); 1286e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (((flags & IS_EMPTY) != 0) != (data == null)) { 1296e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor throw new IllegalArgumentException("Bad flags: " + flags); 1306e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor } 1316e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor 1326e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTag = tag; 1336e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTimeMillis = millis; 1346e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mData = data; 1356e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor = null; 1366e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFlags = flags; 137952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 138952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 139952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 140952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Create a new Entry with streaming data contents. 141952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Takes ownership of the ParcelFileDescriptor. 142952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 143952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) { 1446e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (tag == null) throw new NullPointerException("tag == null"); 1456e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (((flags & IS_EMPTY) != 0) != (data == null)) { 1466e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor throw new IllegalArgumentException("Bad flags: " + flags); 1476e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor } 1486e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor 1496e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTag = tag; 1506e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mTimeMillis = millis; 1516e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mData = null; 1526e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor = data; 1536e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFlags = flags; 154952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 155952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 156952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 157952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Create a new Entry with the contents read from a file. 158952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * The file will be read when the entry's contents are requested. 159952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 160952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry(String tag, long millis, File data, int flags) throws IOException { 1616e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (tag == null) throw new NullPointerException("tag == null"); 1626e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if ((flags & IS_EMPTY) != 0) throw new IllegalArgumentException("Bad flags: " + flags); 163952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 164952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor mTag = tag; 165952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor mTimeMillis = millis; 1666e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mData = null; 1676e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor = ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY); 168952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor mFlags = flags; 169952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 170952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 171952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** Close the input stream associated with this entry. */ 172952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public void close() { 173952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { } 174952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 175952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 176952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** @return the tag originally attached to the entry. */ 177952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public String getTag() { return mTag; } 178952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 179952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** @return time when the entry was originally created. */ 180952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public long getTimeMillis() { return mTimeMillis; } 181952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 18295173b14d65cd04ec88d4384b41a80319e432d0bBrad Fitzpatrick /** @return flags describing the content returned by {@link #getInputStream()}. */ 183952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses. 184952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 185952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 186952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param maxBytes of string to return (will truncate at this length). 187952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @return the uncompressed text contents of the entry, null if the entry is not text. 188952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 189952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public String getText(int maxBytes) { 190952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor if ((mFlags & IS_TEXT) == 0) return null; 191952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor if (mData != null) return new String(mData, 0, Math.min(maxBytes, mData.length)); 192952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 193952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor InputStream is = null; 194952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor try { 195952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor is = getInputStream(); 1966e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (is == null) return null; 197952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor byte[] buf = new byte[maxBytes]; 198e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg int readBytes = 0; 199e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg int n = 0; 200e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg while (n >= 0 && (readBytes += n) < maxBytes) { 201e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg n = is.read(buf, readBytes, maxBytes - readBytes); 202e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg } 203e9f18815218b2ff1f01ea16f2eb0dd17504a9cf3Christian Lindeberg return new String(buf, 0, readBytes); 204952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } catch (IOException e) { 205952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor return null; 206952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } finally { 207952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor try { if (is != null) is.close(); } catch (IOException e) {} 208952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 209952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 210952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 211952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** @return the uncompressed contents of the entry, or null if the contents were lost */ 212952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public InputStream getInputStream() throws IOException { 213952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor InputStream is; 214952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor if (mData != null) { 215952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor is = new ByteArrayInputStream(mData); 216952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } else if (mFileDescriptor != null) { 217952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor); 218952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } else { 219952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor return null; 220952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 221952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is; 222952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 223952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 224952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() { 225952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry[] newArray(int size) { return new Entry[size]; } 226952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry createFromParcel(Parcel in) { 2276e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor String tag = in.readString(); 2286e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor long millis = in.readLong(); 2296e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor int flags = in.readInt(); 2306e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if ((flags & HAS_BYTE_ARRAY) != 0) { 2316e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor return new Entry(tag, millis, in.createByteArray(), flags & ~HAS_BYTE_ARRAY); 2326e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor } else { 233ba953230f71e5117d819d9e7153da8304b141695Tim Kilbourn ParcelFileDescriptor pfd = ParcelFileDescriptor.CREATOR.createFromParcel(in); 234ba953230f71e5117d819d9e7153da8304b141695Tim Kilbourn return new Entry(tag, millis, pfd, flags); 2356e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor } 236952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 237952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor }; 238952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 239952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public int describeContents() { 240952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; 241952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 242952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 243952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public void writeToParcel(Parcel out, int flags) { 244952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor out.writeString(mTag); 245952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor out.writeLong(mTimeMillis); 246952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor if (mFileDescriptor != null) { 2476e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor out.writeInt(mFlags & ~HAS_BYTE_ARRAY); // Clear bit just to be safe 2486e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor mFileDescriptor.writeToParcel(out, flags); 249952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } else { 2506e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor out.writeInt(mFlags | HAS_BYTE_ARRAY); 2516e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor out.writeByteArray(mData); 252952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 253952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 254952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 255952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 256952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** {@hide} */ 257b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey public DropBoxManager(Context context, IDropBoxManagerService service) { 258b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey mContext = context; 259b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey mService = service; 260b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey } 261952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 262952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 263952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Create a dummy instance for testing. All methods will fail unless 264952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * overridden with an appropriate mock implementation. To obtain a 265952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * functional instance, use {@link android.content.Context#getSystemService}. 266952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 267b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey protected DropBoxManager() { 268b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey mContext = null; 269b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey mService = null; 270b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey } 271952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 272952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 273952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Stores human-readable text. The data may be discarded eventually (or even 274952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * immediately) if space is limited, or ignored entirely if the tag has been 275952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * blocked (see {@link #isTagEnabled}). 276952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 277952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param tag describing the type of entry being stored 278952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param data value to store 279952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 280952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public void addText(String tag, String data) { 281f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey try { 282f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey mService.add(new Entry(tag, 0, data)); 283f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } catch (RemoteException e) { 284b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey if (e instanceof TransactionTooLargeException 285b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { 286b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey Log.e(TAG, "App sent too much data, so it was ignored", e); 287b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey return; 288b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey } 289f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey throw e.rethrowFromSystemServer(); 290f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } 291952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 292952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 293952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 294952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Stores binary data, which may be ignored or discarded as with {@link #addText}. 295952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 296952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param tag describing the type of entry being stored 297952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param data value to store 298952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param flags describing the data 299952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 300952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public void addData(String tag, byte[] data, int flags) { 3016e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (data == null) throw new NullPointerException("data == null"); 302f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey try { 303f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey mService.add(new Entry(tag, 0, data, flags)); 304f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } catch (RemoteException e) { 305b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey if (e instanceof TransactionTooLargeException 306b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { 307b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey Log.e(TAG, "App sent too much data, so it was ignored", e); 308b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey return; 309b8e8a91f54f9f11a5936611c00d198ed21824854Jeff Sharkey } 310f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey throw e.rethrowFromSystemServer(); 311f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } 312952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 313952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 314952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 315eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor * Stores the contents of a file, which may be ignored or discarded as with 316eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor * {@link #addText}. 317952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 318952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param tag describing the type of entry being stored 319eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor * @param file to read from 320952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param flags describing the data 321eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor * @throws IOException if the file can't be opened 322952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 323eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor public void addFile(String tag, File file, int flags) throws IOException { 3246e6d60d4c85ce440d9ef5e5f36e708ed0ced65c6Dan Egnor if (file == null) throw new NullPointerException("file == null"); 325eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor Entry entry = new Entry(tag, 0, file, flags); 326eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor try { 32714418945bdc7a9c2e1cba8deaac5cb6dddfd6412Brad Fitzpatrick mService.add(entry); 328eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor } catch (RemoteException e) { 329f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey throw e.rethrowFromSystemServer(); 330eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor } finally { 331eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor entry.close(); 332eb7a7d57ca50f85b054edadab766b51ff22a2dfdDan Egnor } 333952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 334952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 335952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 336952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * Checks any blacklists (set in system settings) to see whether a certain 337952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * tag is allowed. Entries with disabled tags will be dropped immediately, 338952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * so you can save the work of actually constructing and sending the data. 339952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 340952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param tag that would be used in {@link #addText} or {@link #addFile} 341952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @return whether events with that tag would be accepted 342952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 343952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public boolean isTagEnabled(String tag) { 344f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey try { 345f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey return mService.isTagEnabled(tag); 346f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } catch (RemoteException e) { 347f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey throw e.rethrowFromSystemServer(); 348f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } 349952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 350952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 351952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor /** 35230f5c8fede241e7560f4a33e48af3a4627fd5efcBrad Fitzpatrick * Gets the next entry from the drop box <em>after</em> the specified time. 35330f5c8fede241e7560f4a33e48af3a4627fd5efcBrad Fitzpatrick * Requires <code>android.permission.READ_LOGS</code>. You must always call 354952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * {@link Entry#close()} on the return value! 355952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * 356952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param tag of entry to look for, null for all tags 357952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @param msec time of the last entry seen 358952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor * @return the next entry, or null if there are no more entries 359952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor */ 360952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor public Entry getNextEntry(String tag, long msec) { 361f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey try { 362f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey return mService.getNextEntry(tag, msec); 363f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } catch (RemoteException e) { 364f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey throw e.rethrowFromSystemServer(); 365f8880561e67e1da246970b49b14285efd4164ab1Jeff Sharkey } 366952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor } 367952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor 368952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor // TODO: It may be useful to have some sort of notification mechanism 369952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor // when data is added to the dropbox, for demand-driven readers -- 370952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor // for now readers need to poll the dropbox to find new data. 371952402704a175ba27f6c89dff1ada634c5ce5626Dan Egnor} 372