Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4410ec8f authored by Dan Egnor's avatar Dan Egnor
Browse files

Framework-side DropBox service that maintains a size-bounded

queue of data chunks (sort of a blob-oriented logcat).

In the future, this will be coupled with a revised checkin service that
would actually upload this data.
parent 332c7934
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ LOCAL_SRC_FILES += \
	core/java/android/hardware/ISensorService.aidl \
	core/java/android/net/IConnectivityManager.aidl \
	core/java/android/os/ICheckinService.aidl \
	core/java/android/os/IDropBox.aidl \
	core/java/android/os/IHardwareService.aidl \
	core/java/android/os/IMessenger.aidl \
	core/java/android/os/IMountService.aidl \
@@ -216,6 +217,7 @@ aidl_files := \
	frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \
	frameworks/base/core/java/android/net/Uri.aidl \
	frameworks/base/core/java/android/os/Bundle.aidl \
	frameworks/base/core/java/android/os/DropBoxEntry.aidl \
	frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
	frameworks/base/core/java/android/os/ParcelUuid.aidl \
	frameworks/base/core/java/android/view/KeyEvent.aidl \
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

parcelable DropBoxEntry;
+163 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.zip.GZIPInputStream;

/**
 * A single entry retrieved from an {@link IDropBox} implementation.
 * This may include a reference to a stream, so you must call
 * {@link #close()} when you are done using it.
 *
 * {@pending}
 */
public class DropBoxEntry implements Parcelable {
    private final String mTag;
    private final long mTimeMillis;

    private final String mText;
    private final ParcelFileDescriptor mFileDescriptor;
    private final int mFlags;

    /** Flag value: Entry's content was deleted to save space. */
    public static final int IS_EMPTY = 1;

    /** Flag value: Content is human-readable UTF-8 text (possibly compressed). */
    public static final int IS_TEXT = 2;

    /** Flag value: Content can been decompressed with {@link GZIPOutputStream}. */
    public static final int IS_GZIPPED = 4;

    /** Create a new DropBoxEntry with the specified contents. */
    public DropBoxEntry(String tag, long timeMillis, String text) {
        if (tag == null || text == null) throw new NullPointerException();
        mTag = tag;
        mTimeMillis = timeMillis;
        mText = text;
        mFileDescriptor = null;
        mFlags = IS_TEXT;
    }

    /** Create a new DropBoxEntry with the specified contents. */
    public DropBoxEntry(String tag, long millis, File data, int flags) throws IOException {
        if (tag == null) throw new NullPointerException();
        if (((flags & IS_EMPTY) != 0) != (data == null)) throw new IllegalArgumentException();

        mTag = tag;
        mTimeMillis = millis;
        mText = null;
        mFlags = flags;
        mFileDescriptor = data == null ? null :
                ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY);
    }

    /** Internal constructor for CREATOR.createFromParcel(). */
    private DropBoxEntry(String tag, long millis, Object value, int flags) {
        if (tag == null) throw new NullPointerException();
        if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();

        mTag = tag;
        mTimeMillis = millis;
        mFlags = flags;

        if (value == null) {
            mText = null;
            mFileDescriptor = null;
        } else if (value instanceof String) {
            if ((flags & IS_TEXT) == 0) throw new IllegalArgumentException();
            mText = (String) value;
            mFileDescriptor = null;
        } else if (value instanceof ParcelFileDescriptor) {
            mText = null;
            mFileDescriptor = (ParcelFileDescriptor) value;
        } else {
            throw new IllegalArgumentException();
        }
    }

    /** Close the input stream associated with this entry. */
    public synchronized void close() {
        try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { }
    }

    /** @return the tag originally attached to the entry. */
    public String getTag() { return mTag; }

    /** @return time when the entry was originally created. */
    public long getTimeMillis() { return mTimeMillis; }

    /** @return flags describing the content returned by @{link #getInputStream()}. */
    public int getFlags() { return mFlags & ~IS_GZIPPED; }  // getInputStream() decompresses.

    /**
     * @param maxLength of string to return (will truncate at this length).
     * @return the uncompressed text contents of the entry, null if the entry is not text.
     */
    public String getText(int maxLength) {
        if (mText != null) return mText.substring(0, Math.min(maxLength, mText.length()));
        if ((mFlags & IS_TEXT) == 0) return null;

        try {
            InputStream stream = getInputStream();
            if (stream == null) return null;
            char[] buf = new char[maxLength];
            InputStreamReader reader = new InputStreamReader(stream);
            return new String(buf, 0, Math.max(0, reader.read(buf)));
        } catch (IOException e) {
            return null;
        }
    }

    /** @return the uncompressed contents of the entry, or null if the contents were lost */
    public InputStream getInputStream() throws IOException {
        if (mText != null) return new ByteArrayInputStream(mText.getBytes("UTF8"));
        if (mFileDescriptor == null) return null;
        InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
        return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
    }

    public static final Parcelable.Creator<DropBoxEntry> CREATOR = new Parcelable.Creator() {
        public DropBoxEntry[] newArray(int size) { return new DropBoxEntry[size]; }
        public DropBoxEntry createFromParcel(Parcel in) {
            return new DropBoxEntry(
                    in.readString(), in.readLong(), in.readValue(null), in.readInt());
        }
    };

    public int describeContents() {
        return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(mTag);
        out.writeLong(mTimeMillis);
        if (mFileDescriptor != null) {
            out.writeValue(mFileDescriptor);
        } else {
            out.writeValue(mText);
        }
        out.writeInt(mFlags);
    }
}
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.os.DropBoxEntry;
import android.os.ParcelFileDescriptor;

/**
 * Enqueues chunks of data (from various sources -- application crashes, kernel
 * log records, etc.).  The queue is size bounded and will drop old data if the
 * enqueued data exceeds the maximum size.
 *
 * <p>This interface is implemented by a system service you can access:
 *
 * <pre>IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));</pre>
 *
 * <p>Other system services and debugging tools may scan the drop box to upload
 * entries for processing.
 *
 * {@pending}
 */
interface IDropBox {
    /**
     * Stores human-readable text.  The data may be discarded eventually (or even
     * immediately) if space is limited, or ignored entirely if the tag has been
     * blocked (see {@link #isTagEnabled}).
     *
     * @param tag describing the type of entry being stored
     * @param data value to store
     */
    void addText(String tag, String data);

    /**
     * Stores binary data.  The data may be ignored or discarded as with
     * {@link #addText}.
     *
     * @param tag describing the type of entry being stored
     * @param data value to store
     * @param flags describing the data, defined in {@link DropBoxEntry}
     */
    void addData(String tag, in byte[] data, int flags);

    /**
     * Stores data read from a file descriptor.  The data may be ignored or
     * discarded as with {@link #addText}.  You must close your
     * ParcelFileDescriptor object after calling this method!
     *
     * @param tag describing the type of entry being stored
     * @param data file descriptor to read from
     * @param flags describing the data, defined in {@link DropBoxEntry}
     */
    void addFile(String tag, in ParcelFileDescriptor data, int flags);

    /**
     * Checks any blacklists (set in system settings) to see whether a certain
     * tag is allowed.  Entries with disabled tags will be dropped immediately,
     * so you can save the work of actually constructing and sending the data.
     *
     * @param tag that would be used in {@link #addText} or {@link #addFile}
     * @return whether events with that tag would be accepted
     */
    boolean isTagEnabled(String tag);

    /**
     * Gets the next entry from the drop box *after* the specified time.
     * Requires android.permission.READ_LOGS.
     *
     * @param millis time of the last entry seen
     * @return the next entry, or null if there are no more entries
     */
    DropBoxEntry getNextEntry(long millis);

    // TODO: It may be useful to have some sort of notification mechanism
    // when data is added to the dropbox, for demand-driven readers --
    // for now readers need to poll the dropbox to find new data.
}
+26 −1
Original line number Diff line number Diff line
@@ -3611,7 +3611,6 @@ public final class Settings {
         */
        public static final String SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT =
                "search_per_source_concurrent_query_limit";

        /**
         * Flag for allowing ActivityManagerService to send ACTION_APP_ERROR intents
         * on application crashes and ANRs. If this is disabled, the crash/ANR dialog
@@ -3625,6 +3624,32 @@ public final class Settings {
         */
        public static final String LAST_KMSG_KB = "last_kmsg_kb";

        /**
         * Maximum age of entries kept by {@link android.os.IDropBox}.
         */
        public static final String DROPBOX_AGE_SECONDS =
                "dropbox_age_seconds";
        /**
         * Maximum amount of disk space used by {@link android.os.IDropBox} no matter what.
         */
        public static final String DROPBOX_QUOTA_KB =
                "dropbox_quota_kb";
        /**
         * Percent of free disk (excluding reserve) which {@link android.os.IDropBox} will use.
         */
        public static final String DROPBOX_QUOTA_PERCENT =
                "dropbox_quota_percent";
        /**
         * Percent of total disk which {@link android.os.IDropBox} will never dip into.
         */
        public static final String DROPBOX_RESERVE_PERCENT =
                "dropbox_reserve_percent";
        /**
         * Prefix for per-tag dropbox disable/enable settings.
         */
        public static final String DROPBOX_TAG_PREFIX =
                "dropbox:";

        /**
         * @deprecated
         * @hide
Loading