All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.internal.os.TransferPipe Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2011 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 com.android.internal.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;

import libcore.io.IoUtils;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Helper for transferring data through a pipe from a client app.
 */
public class TransferPipe implements Runnable, Closeable {
    static final String TAG = "TransferPipe";
    static final boolean DEBUG = false;

    static final long DEFAULT_TIMEOUT = 5000;  // 5 seconds

    final Thread mThread;
    final ParcelFileDescriptor[] mFds;

    FileDescriptor mOutFd;
    long mEndTime;
    String mFailure;
    boolean mComplete;

    String mBufferPrefix;

    interface Caller {
        void go(IInterface iface, FileDescriptor fd, String prefix,
                String[] args) throws RemoteException;
    }

    public TransferPipe() throws IOException {
        this(null);
    }

    public TransferPipe(String bufferPrefix) throws IOException {
        this(bufferPrefix, "TransferPipe");
    }

    protected TransferPipe(String bufferPrefix, String threadName) throws IOException {
        mThread = new Thread(this, threadName);
        mFds = ParcelFileDescriptor.createPipe();
        mBufferPrefix = bufferPrefix;
    }

    ParcelFileDescriptor getReadFd() {
        return mFds[0];
    }

    public ParcelFileDescriptor getWriteFd() {
        return mFds[1];
    }

    public void setBufferPrefix(String prefix) {
        mBufferPrefix = prefix;
    }

    public static void dumpAsync(IBinder binder, FileDescriptor out, String[] args)
            throws IOException, RemoteException {
        goDump(binder, out, args);
    }

    /**
     * Read raw bytes from a service's dump function.
     *
     * 

This can be used for dumping {@link android.util.proto.ProtoOutputStream protos}. * * @param binder The service providing the data * @param args The arguments passed to the dump function of the service */ public static byte[] dumpAsync(@NonNull IBinder binder, @Nullable String... args) throws IOException, RemoteException { ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); try { TransferPipe.dumpAsync(binder, pipe[1].getFileDescriptor(), args); // Data is written completely when dumpAsync is done pipe[1].close(); pipe[1] = null; byte[] buffer = new byte[4096]; try (ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream()) { try (FileInputStream is = new FileInputStream(pipe[0].getFileDescriptor())) { while (true) { int numRead = is.read(buffer); if (numRead == -1) { break; } combinedBuffer.write(buffer, 0, numRead); } } return combinedBuffer.toByteArray(); } } finally { pipe[0].close(); IoUtils.closeQuietly(pipe[1]); } } static void go(Caller caller, IInterface iface, FileDescriptor out, String prefix, String[] args) throws IOException, RemoteException { go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT); } static void go(Caller caller, IInterface iface, FileDescriptor out, String prefix, String[] args, long timeout) throws IOException, RemoteException { if ((iface.asBinder()) instanceof Binder) { // This is a local object... just call it directly. try { caller.go(iface, out, prefix, args); } catch (RemoteException e) { } return; } try (TransferPipe tp = new TransferPipe()) { caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args); tp.go(out, timeout); } } static void goDump(IBinder binder, FileDescriptor out, String[] args) throws IOException, RemoteException { goDump(binder, out, args, DEFAULT_TIMEOUT); } static void goDump(IBinder binder, FileDescriptor out, String[] args, long timeout) throws IOException, RemoteException { if (binder instanceof Binder) { // This is a local object... just call it directly. try { binder.dump(out, args); } catch (RemoteException e) { } return; } try (TransferPipe tp = new TransferPipe()) { binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args); tp.go(out, timeout); } } public void go(FileDescriptor out) throws IOException { go(out, DEFAULT_TIMEOUT); } public void go(FileDescriptor out, long timeout) throws IOException { try { synchronized (this) { mOutFd = out; mEndTime = SystemClock.uptimeMillis() + timeout; if (DEBUG) Slog.i(TAG, "read=" + getReadFd() + " write=" + getWriteFd() + " out=" + out); // Close the write fd, so we know when the other side is done. closeFd(1); mThread.start(); while (mFailure == null && !mComplete) { long waitTime = mEndTime - SystemClock.uptimeMillis(); if (waitTime <= 0) { if (DEBUG) Slog.i(TAG, "TIMEOUT!"); mThread.interrupt(); throw new IOException("Timeout"); } try { wait(waitTime); } catch (InterruptedException e) { } } if (DEBUG) Slog.i(TAG, "Finished: " + mFailure); if (mFailure != null) { throw new IOException(mFailure); } } } finally { kill(); } } void closeFd(int num) { if (mFds[num] != null) { if (DEBUG) Slog.i(TAG, "Closing: " + mFds[num]); try { mFds[num].close(); } catch (IOException e) { } mFds[num] = null; } } @Override public void close() { kill(); } public void kill() { synchronized (this) { closeFd(0); closeFd(1); } } protected OutputStream getNewOutputStream() { return new FileOutputStream(mOutFd); } @Override public void run() { final byte[] buffer = new byte[1024]; final FileInputStream fis; final OutputStream fos; synchronized (this) { ParcelFileDescriptor readFd = getReadFd(); if (readFd == null) { Slog.w(TAG, "Pipe has been closed..."); return; } fis = new FileInputStream(readFd.getFileDescriptor()); fos = getNewOutputStream(); } if (DEBUG) Slog.i(TAG, "Ready to read pipe..."); byte[] bufferPrefix = null; boolean needPrefix = true; if (mBufferPrefix != null) { bufferPrefix = mBufferPrefix.getBytes(); } int size; try { while ((size=fis.read(buffer)) > 0) { if (DEBUG) Slog.i(TAG, "Got " + size + " bytes"); if (bufferPrefix == null) { fos.write(buffer, 0, size); } else { int start = 0; for (int i=0; i start) { fos.write(buffer, start, i-start); } start = i; if (needPrefix) { fos.write(bufferPrefix); needPrefix = false; } do { i++; } while (i start) { fos.write(buffer, start, size-start); } } } if (DEBUG) Slog.i(TAG, "End of pipe: size=" + size); if (mThread.isInterrupted()) { if (DEBUG) Slog.i(TAG, "Interrupted!"); } } catch (IOException e) { synchronized (this) { mFailure = e.toString(); notifyAll(); return; } } synchronized (this) { mComplete = true; notifyAll(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy