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

Commit 0b2278d9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "crMoveBack" into main

* changes:
  [CrashRecovery] Moving the files back
  Revert^3 "Update the BackgroundThread dependency"
  Revert^3 "Utils required for CrashRecovery module"
parents 1bd43fbb 14e87269
Loading
Loading
Loading
Loading
+0 −115
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.utils;

import android.annotation.NonNull;
import android.annotation.Nullable;

import java.io.File;
import java.util.List;
import java.util.Objects;

/**
 * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
 *
 * @hide
 */
public class ArrayUtils {
    private ArrayUtils() { /* cannot be instantiated */ }
    public static final File[] EMPTY_FILE = new File[0];


    /**
     * Return first index of {@code value} in {@code array}, or {@code -1} if
     * not found.
     */
    public static <T> int indexOf(@Nullable T[] array, T value) {
        if (array == null) return -1;
        for (int i = 0; i < array.length; i++) {
            if (Objects.equals(array[i], value)) return i;
        }
        return -1;
    }

    /** @hide */
    public static @NonNull File[] defeatNullable(@Nullable File[] val) {
        return (val != null) ? val : EMPTY_FILE;
    }

    /**
     * Checks if given array is null or has zero elements.
     */
    public static boolean isEmpty(@Nullable int[] array) {
        return array == null || array.length == 0;
    }

    /**
     * True if the byte array is null or has length 0.
     */
    public static boolean isEmpty(@Nullable byte[] array) {
        return array == null || array.length == 0;
    }

    /**
     * Converts from List of bytes to byte array
     * @param list
     * @return byte[]
     */
    public static byte[] toPrimitive(List<byte[]> list) {
        if (list.size() == 0) {
            return new byte[0];
        }
        int byteLen = list.get(0).length;
        byte[] array = new byte[list.size() * byteLen];
        for (int i = 0; i < list.size(); i++) {
            for (int j = 0; j < list.get(i).length; j++) {
                array[i * byteLen + j] = list.get(i)[j];
            }
        }
        return array;
    }

    /**
     * Adds value to given array if not already present, providing set-like
     * behavior.
     */
    public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
        return appendInt(cur, val, false);
    }

    /**
     * Adds value to given array.
     */
    public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
            boolean allowDuplicates) {
        if (cur == null) {
            return new int[] { val };
        }
        final int n = cur.length;
        if (!allowDuplicates) {
            for (int i = 0; i < n; i++) {
                if (cur[i] == val) {
                    return cur;
                }
            }
        }
        int[] ret = new int[n + 1];
        System.arraycopy(cur, 0, ret, 0, n);
        ret[n] = val;
        return ret;
    }
}
+0 −103
Original line number Diff line number Diff line
/*
 *  * Copyright (C) 2024 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.utils;

import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerThread;

import com.android.internal.annotations.GuardedBy;

import java.util.concurrent.Executor;

/**
 * Thread for asynchronous event processing. This thread is configured as
 * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
 * resources will be dedicated to it, and it will "have less chance of impacting
 * the responsiveness of the user interface."
 * <p>
 * This thread is best suited for tasks that the user is not actively waiting
 * for, or for tasks that the user expects to be executed eventually.
 *
 * @see com.android.internal.os.BackgroundThread
 *
 * TODO: b/326916057 depend on modules-utils-backgroundthread instead
 * @hide
 */
public final class BackgroundThread extends HandlerThread {
    private static final Object sLock = new Object();

    @GuardedBy("sLock")
    private static BackgroundThread sInstance;
    @GuardedBy("sLock")
    private static Handler sHandler;
    @GuardedBy("sLock")
    private static HandlerExecutor sHandlerExecutor;

    private BackgroundThread() {
        super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
    }

    @GuardedBy("sLock")
    private static void ensureThreadLocked() {
        if (sInstance == null) {
            sInstance = new BackgroundThread();
            sInstance.start();
            sHandler = new Handler(sInstance.getLooper());
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
    }

    /**
     * Get the singleton instance of this class.
     *
     * @return the singleton instance of this class
     */
    @NonNull
    public static BackgroundThread get() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sInstance;
        }
    }

    /**
     * Get the singleton {@link Handler} for this class.
     *
     * @return the singleton {@link Handler} for this class.
     */
    @NonNull
    public static Handler getHandler() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandler;
        }
    }

    /**
     * Get the singleton {@link Executor} for this class.
     *
     * @return the singleton {@link Executor} for this class.
     */
    @NonNull
    public static Executor getExecutor() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
    }
}
+0 −128
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.utils;

import android.annotation.NonNull;
import android.annotation.Nullable;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Bits and pieces copied from hidden API of android.os.FileUtils.
 *
 * @hide
 */
public class FileUtils {
    /**
     * Read a text file into a String, optionally limiting the length.
     *
     * @param file     to read (will not seek, so things like /proc files are OK)
     * @param max      length (positive for head, negative of tail, 0 for no limit)
     * @param ellipsis to add of the file was truncated (can be null)
     * @return the contents of the file, possibly truncated
     * @throws IOException if something goes wrong reading the file
     * @hide
     */
    public static @Nullable String readTextFile(@Nullable File file, @Nullable int max,
            @Nullable String ellipsis) throws IOException {
        InputStream input = new FileInputStream(file);
        // wrapping a BufferedInputStream around it because when reading /proc with unbuffered
        // input stream, bytes read not equal to buffer size is not necessarily the correct
        // indication for EOF; but it is true for BufferedInputStream due to its implementation.
        BufferedInputStream bis = new BufferedInputStream(input);
        try {
            long size = file.length();
            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes
                if (size > 0 && (max == 0 || size < max)) max = (int) size;
                byte[] data = new byte[max + 1];
                int length = bis.read(data);
                if (length <= 0) return "";
                if (length <= max) return new String(data, 0, length);
                if (ellipsis == null) return new String(data, 0, max);
                return new String(data, 0, max) + ellipsis;
            } else if (max < 0) {  // "tail" mode: keep the last N
                int len;
                boolean rolled = false;
                byte[] last = null;
                byte[] data = null;
                do {
                    if (last != null) rolled = true;
                    byte[] tmp = last;
                    last = data;
                    data = tmp;
                    if (data == null) data = new byte[-max];
                    len = bis.read(data);
                } while (len == data.length);

                if (last == null && len <= 0) return "";
                if (last == null) return new String(data, 0, len);
                if (len > 0) {
                    rolled = true;
                    System.arraycopy(last, len, last, 0, last.length - len);
                    System.arraycopy(data, 0, last, last.length - len, len);
                }
                if (ellipsis == null || !rolled) return new String(last);
                return ellipsis + new String(last);
            } else {  // "cat" mode: size unknown, read it all in streaming fashion
                ByteArrayOutputStream contents = new ByteArrayOutputStream();
                int len;
                byte[] data = new byte[1024];
                do {
                    len = bis.read(data);
                    if (len > 0) contents.write(data, 0, len);
                } while (len == data.length);
                return contents.toString();
            }
        } finally {
            bis.close();
            input.close();
        }
    }

    /**
     * Perform an fsync on the given FileOutputStream. The stream at this
     * point must be flushed but not yet closed.
     *
     * @hide
     */
    public static boolean sync(FileOutputStream stream) {
        try {
            if (stream != null) {
                stream.getFD().sync();
            }
            return true;
        } catch (IOException e) {
        }
        return false;
    }

    /**
     * List the files in the directory or return empty file.
     *
     * @hide
     */
    public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
        return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
            : ArrayUtils.EMPTY_FILE;
    }
}
+0 −46
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.utils;

import android.annotation.NonNull;
import android.os.Handler;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;

/**
 * An adapter {@link Executor} that posts all executed tasks onto the given
 * {@link Handler}.
 *
 * TODO: b/326916057 depend on modules-utils-backgroundthread instead
 * @hide
 */
public class HandlerExecutor implements Executor {
    private final Handler mHandler;

    public HandlerExecutor(@NonNull Handler handler) {
        mHandler = Objects.requireNonNull(handler);
    }

    @Override
    public void execute(Runnable command) {
        if (!mHandler.post(command)) {
            throw new RejectedExecutionException(mHandler + " is shutting down");
        }
    }
}
+0 −188
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.utils;

import libcore.util.EmptyArray;

import java.util.NoSuchElementException;

/**
 * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java
 *
 * @hide
 */
public class LongArrayQueue {

    private long[] mValues;
    private int mSize;
    private int mHead;
    private int mTail;

    private long[] newUnpaddedLongArray(int num) {
        return new long[num];
    }
    /**
     * Initializes a queue with the given starting capacity.
     *
     * @param initialCapacity the capacity.
     */
    public LongArrayQueue(int initialCapacity) {
        if (initialCapacity == 0) {
            mValues = EmptyArray.LONG;
        } else {
            mValues = newUnpaddedLongArray(initialCapacity);
        }
        mSize = 0;
        mHead = mTail = 0;
    }

    /**
     * Initializes a queue with default starting capacity.
     */
    public LongArrayQueue() {
        this(16);
    }

    /** @hide */
    public static int growSize(int currentSize) {
        return currentSize <= 4 ? 8 : currentSize * 2;
    }

    private void grow() {
        if (mSize < mValues.length) {
            throw new IllegalStateException("Queue not full yet!");
        }
        final int newSize = growSize(mSize);
        final long[] newArray = newUnpaddedLongArray(newSize);
        final int r = mValues.length - mHead; // Number of elements on and to the right of head.
        System.arraycopy(mValues, mHead, newArray, 0, r);
        System.arraycopy(mValues, 0, newArray, r, mHead);
        mValues = newArray;
        mHead = 0;
        mTail = mSize;
    }

    /**
     * Returns the number of elements in the queue.
     */
    public int size() {
        return mSize;
    }

    /**
     * Removes all elements from this queue.
     */
    public void clear() {
        mSize = 0;
        mHead = mTail = 0;
    }

    /**
     * Adds a value to the tail of the queue.
     *
     * @param value the value to be added.
     */
    public void addLast(long value) {
        if (mSize == mValues.length) {
            grow();
        }
        mValues[mTail] = value;
        mTail = (mTail + 1) % mValues.length;
        mSize++;
    }

    /**
     * Removes an element from the head of the queue.
     *
     * @return the element at the head of the queue.
     * @throws NoSuchElementException if the queue is empty.
     */
    public long removeFirst() {
        if (mSize == 0) {
            throw new NoSuchElementException("Queue is empty!");
        }
        final long ret = mValues[mHead];
        mHead = (mHead + 1) % mValues.length;
        mSize--;
        return ret;
    }

    /**
     * Returns the element at the given position from the head of the queue, where 0 represents the
     * head of the queue.
     *
     * @param position the position from the head of the queue.
     * @return the element found at the given position.
     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
     *                                   {@code position} >= {@link #size()}
     */
    public long get(int position) {
        if (position < 0 || position >= mSize) {
            throw new IndexOutOfBoundsException("Index " + position
                + " not valid for a queue of size " + mSize);
        }
        final int index = (mHead + position) % mValues.length;
        return mValues[index];
    }

    /**
     * Returns the element at the head of the queue, without removing it.
     *
     * @return the element at the head of the queue.
     * @throws NoSuchElementException if the queue is empty
     */
    public long peekFirst() {
        if (mSize == 0) {
            throw new NoSuchElementException("Queue is empty!");
        }
        return mValues[mHead];
    }

    /**
     * Returns the element at the tail of the queue.
     *
     * @return the element at the tail of the queue.
     * @throws NoSuchElementException if the queue is empty.
     */
    public long peekLast() {
        if (mSize == 0) {
            throw new NoSuchElementException("Queue is empty!");
        }
        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
        return mValues[index];
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        if (mSize <= 0) {
            return "{}";
        }

        final StringBuilder buffer = new StringBuilder(mSize * 64);
        buffer.append('{');
        buffer.append(get(0));
        for (int i = 1; i < mSize; i++) {
            buffer.append(", ");
            buffer.append(get(i));
        }
        buffer.append('}');
        return buffer.toString();
    }
}
Loading