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

Commit 68fa15e3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes Ie9efb041,I2b48593f

* changes:
  Use correct density to calculcate min dimen.
  Implement launch bounds logic in Android (1/3)
parents 2364b8b9 4a48a7f9
Loading
Loading
Loading
Loading
+11 −9
Original line number Original line Diff line number Diff line
@@ -50,7 +50,6 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
@@ -97,7 +96,6 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;

import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.MAX_VALUE;


import android.Manifest;
import android.Manifest;
@@ -132,6 +130,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -156,6 +155,7 @@ import android.provider.MediaStore;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.EventLog;
import android.util.IntArray;
import android.util.IntArray;
import android.util.MergedConfiguration;
import android.util.MergedConfiguration;
@@ -445,7 +445,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D


    // The default minimal size that will be used if the activity doesn't specify its minimal size.
    // The default minimal size that will be used if the activity doesn't specify its minimal size.
    // It will be calculated when the default display gets added.
    // It will be calculated when the default display gets added.
    int mDefaultMinSizeOfResizeableTask = -1;
    int mDefaultMinSizeOfResizeableTaskDp = -1;


    // Whether tasks have moved and we need to rank the tasks before next OOM scoring
    // Whether tasks have moved and we need to rank the tasks before next OOM scoring
    private boolean mTaskLayersChanged = true;
    private boolean mTaskLayersChanged = true;
@@ -689,8 +689,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                mDefaultDisplay = activityDisplay;
                mDefaultDisplay = activityDisplay;
            }
            }
            addChild(activityDisplay, ActivityDisplay.POSITION_TOP);
            addChild(activityDisplay, ActivityDisplay.POSITION_TOP);
            calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
        }
        }
        calculateDefaultMinimalSizeOfResizeableTasks();


        final ActivityDisplay defaultDisplay = getDefaultDisplay();
        final ActivityDisplay defaultDisplay = getDefaultDisplay();
        mHomeStack = mLastFocusedStack = defaultDisplay.getOrCreateStack(
        mHomeStack = mLastFocusedStack = defaultDisplay.getOrCreateStack(
@@ -4319,7 +4319,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        // The display hasn't been added to ActivityManager yet, create a new record now.
        // The display hasn't been added to ActivityManager yet, create a new record now.
        activityDisplay = new ActivityDisplay(this, display);
        activityDisplay = new ActivityDisplay(this, display);
        addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM);
        addChild(activityDisplay, ActivityDisplay.POSITION_BOTTOM);
        calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
        mWindowManager.onDisplayAdded(displayId);
        mWindowManager.onDisplayAdded(displayId);
        return activityDisplay;
        return activityDisplay;
    }
    }
@@ -4337,10 +4336,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        mActivityDisplays.remove(activityDisplay);
        mActivityDisplays.remove(activityDisplay);
    }
    }


    private void calculateDefaultMinimalSizeOfResizeableTasks(ActivityDisplay display) {
    private void calculateDefaultMinimalSizeOfResizeableTasks() {
        mDefaultMinSizeOfResizeableTask =
        final Resources res = mService.mContext.getResources();
                mService.mContext.getResources().getDimensionPixelSize(
        final float minimalSize = res.getDimension(
                com.android.internal.R.dimen.default_minimal_size_resizable_task);
                com.android.internal.R.dimen.default_minimal_size_resizable_task);
        final DisplayMetrics dm = res.getDisplayMetrics();

        mDefaultMinSizeOfResizeableTaskDp = (int) (minimalSize / dm.density);
    }
    }


    private void handleDisplayRemoved(int displayId) {
    private void handleDisplayRemoved(int displayId) {
+277 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 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.server.am;

import android.os.Process;
import android.os.SystemClock;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.function.Predicate;

/**
 * The common threading logic for persisters to use so that they can run in the same threads.
 * Methods in this class are synchronized on its instance, so caller could also synchronize on
 * its instance to perform modifications in items.
 */
class PersisterQueue {
    private static final String TAG = "PersisterQueue";
    private static final boolean DEBUG = false;

    /** When not flushing don't write out files faster than this */
    private static final long INTER_WRITE_DELAY_MS = 500;

    /**
     * When not flushing delay this long before writing the first file out. This gives the next task
     * being launched a chance to load its resources without this occupying IO bandwidth.
     */
    private static final long PRE_TASK_DELAY_MS = 3000;

    /** The maximum number of entries to keep in the queue before draining it automatically. */
    private static final int MAX_WRITE_QUEUE_LENGTH = 6;

    /** Special value for mWriteTime to mean don't wait, just write */
    private static final long FLUSH_QUEUE = -1;

    /** An {@link WriteQueueItem} that doesn't do anything. Used to trigger {@link
     * Listener#onPreProcessItem}. */
    static final WriteQueueItem EMPTY_ITEM = () -> { };

    private final long mInterWriteDelayMs;
    private final long mPreTaskDelayMs;
    private final LazyTaskWriterThread mLazyTaskWriterThread;
    private final ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<>();

    private final ArrayList<Listener> mListeners = new ArrayList<>();

    /**
     * Value determines write delay mode as follows: < 0 We are Flushing. No delays between writes
     * until the image queue is drained and all tasks needing persisting are written to disk. There
     * is no delay between writes. == 0 We are Idle. Next writes will be delayed by
     * #PRE_TASK_DELAY_MS. > 0 We are Actively writing. Next write will be at this time. Subsequent
     * writes will be delayed by #INTER_WRITE_DELAY_MS.
     */
    private long mNextWriteTime = 0;

    PersisterQueue() {
        this(INTER_WRITE_DELAY_MS, PRE_TASK_DELAY_MS);
    }

    /** Used for tests to reduce waiting time. */
    @VisibleForTesting
    PersisterQueue(long interWriteDelayMs, long preTaskDelayMs) {
        if (interWriteDelayMs < 0 || preTaskDelayMs < 0) {
            throw new IllegalArgumentException("Both inter-write delay and pre-task delay need to"
                    + "be non-negative. inter-write delay: " + interWriteDelayMs
                    + "ms pre-task delay: " + preTaskDelayMs);
        }
        mInterWriteDelayMs = interWriteDelayMs;
        mPreTaskDelayMs = preTaskDelayMs;
        mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
    }

    synchronized void startPersisting() {
        if (!mLazyTaskWriterThread.isAlive()) {
            mLazyTaskWriterThread.start();
        }
    }

    /** Stops persisting thread. Should only be used in tests. */
    @VisibleForTesting
    void stopPersisting() throws InterruptedException {
        if (!mLazyTaskWriterThread.isAlive()) {
            return;
        }

        synchronized (this) {
            mLazyTaskWriterThread.interrupt();
        }
        mLazyTaskWriterThread.join();
    }

    synchronized void addItem(WriteQueueItem item, boolean flush) {
        mWriteQueue.add(item);

        if (flush || mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
            mNextWriteTime = FLUSH_QUEUE;
        } else if (mNextWriteTime == 0) {
            mNextWriteTime = SystemClock.uptimeMillis() + mPreTaskDelayMs;
        }
        notify();
    }

    synchronized <T extends WriteQueueItem> T findLastItem(Predicate<T> predicate, Class<T> clazz) {
        for (int i = mWriteQueue.size() - 1; i >= 0; --i) {
            WriteQueueItem writeQueueItem = mWriteQueue.get(i);
            if (clazz.isInstance(writeQueueItem)) {
                T item = clazz.cast(writeQueueItem);
                if (predicate.test(item)) {
                    return item;
                }
            }
        }

        return null;
    }

    synchronized <T extends WriteQueueItem> void removeItems(Predicate<T> predicate,
            Class<T> clazz) {
        for (int i = mWriteQueue.size() - 1; i >= 0; --i) {
            WriteQueueItem writeQueueItem = mWriteQueue.get(i);
            if (clazz.isInstance(writeQueueItem)) {
                T item = clazz.cast(writeQueueItem);
                if (predicate.test(item)) {
                    if (DEBUG) Slog.d(TAG, "Removing " + item + " from write queue.");
                    mWriteQueue.remove(i);
                }
            }
        }
    }

    synchronized void flush() {
        mNextWriteTime = FLUSH_QUEUE;
        notifyAll();
        do {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        } while (mNextWriteTime == FLUSH_QUEUE);
    }

    void yieldIfQueueTooDeep() {
        boolean stall = false;
        synchronized (this) {
            if (mNextWriteTime == FLUSH_QUEUE) {
                stall = true;
            }
        }
        if (stall) {
            Thread.yield();
        }
    }

    void addListener(Listener listener) {
        mListeners.add(listener);
    }

    private void processNextItem() throws InterruptedException {
        // This part is extracted into a method so that the GC can clearly see the end of the
        // scope of the variable 'item'.  If this part was in the loop in LazyTaskWriterThread, the
        // last item it processed would always "leak".
        // See https://b.corp.google.com/issues/64438652#comment7

        // If mNextWriteTime, then don't delay between each call to saveToXml().
        final WriteQueueItem item;
        synchronized (this) {
            if (mNextWriteTime != FLUSH_QUEUE) {
                // The next write we don't have to wait so long.
                mNextWriteTime = SystemClock.uptimeMillis() + mInterWriteDelayMs;
                if (DEBUG) {
                    Slog.d(TAG, "Next write time may be in " + mInterWriteDelayMs
                            + " msec. (" + mNextWriteTime + ")");
                }
            }

            while (mWriteQueue.isEmpty()) {
                if (mNextWriteTime != 0) {
                    mNextWriteTime = 0; // idle.
                    notify(); // May need to wake up flush().
                }
                // Make sure we exit this thread correctly when interrupted before going to
                // indefinite wait.
                if (Thread.currentThread().isInterrupted()) {
                    throw new InterruptedException();
                }
                if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
                wait();
                // Invariant: mNextWriteTime is either FLUSH_QUEUE or PRE_WRITE_DELAY_MS
                // from now.
            }
            item = mWriteQueue.remove(0);

            long now = SystemClock.uptimeMillis();
            if (DEBUG) {
                Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" + mNextWriteTime
                        + " mWriteQueue.size=" + mWriteQueue.size());
            }
            while (now < mNextWriteTime) {
                if (DEBUG) {
                    Slog.d(TAG, "LazyTaskWriter: waiting " + (mNextWriteTime - now));
                }
                wait(mNextWriteTime - now);
                now = SystemClock.uptimeMillis();
            }

            // Got something to do.
        }

        item.process();
    }

    interface WriteQueueItem {
        void process();
    }

    interface Listener {
        /**
         * Called before {@link PersisterQueue} tries to process next item.
         *
         * Note if the queue is empty, this callback will be called before the indefinite wait. This
         * will be called once when {@link PersisterQueue} starts the internal thread before the
         * indefinite wait.
         *
         * This callback is called w/o locking the instance of {@link PersisterQueue}.
         *
         * @param queueEmpty {@code true} if the queue is empty, which indicates {@link
         * PersisterQueue} is likely to enter indefinite wait; or {@code false} if there is still
         * item to process.
         */
        void onPreProcessItem(boolean queueEmpty);
    }

    private class LazyTaskWriterThread extends Thread {

        private LazyTaskWriterThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            try {
                while (true) {
                    final boolean probablyDone;
                    synchronized (PersisterQueue.this) {
                        probablyDone = mWriteQueue.isEmpty();
                    }

                    for (int i = mListeners.size() - 1; i >= 0; --i) {
                        mListeners.get(i).onPreProcessItem(probablyDone);
                    }

                    processNextItem();
                }
            } catch (InterruptedException e) {
                Slog.e(TAG, "Persister thread is exiting. Should never happen in prod, but"
                        + "it's OK in tests.");
            }
        }
    }
}
+1 −3
Original line number Original line Diff line number Diff line
@@ -30,7 +30,6 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;

import static android.os.Process.SYSTEM_UID;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
@@ -55,7 +54,6 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Environment;
import android.os.Environment;
import android.os.IBinder;
import android.os.IBinder;
@@ -431,7 +429,7 @@ class RecentTasks {
    void onSystemReadyLocked() {
    void onSystemReadyLocked() {
        loadRecentsComponent(mService.mContext.getResources());
        loadRecentsComponent(mService.mContext.getResources());
        mTasks.clear();
        mTasks.clear();
        mTaskPersister.startPersisting();
        mTaskPersister.onSystemReady();
    }
    }


    Bitmap getTaskDescriptionIcon(String path) {
    Bitmap getTaskDescriptionIcon(String path) {
+166 −298

File changed.

Preview size limit exceeded, changes collapsed.

+10 −4
Original line number Original line Diff line number Diff line
@@ -45,7 +45,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
@@ -75,7 +74,6 @@ import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
import static com.android.server.am.TaskRecordProto.STACK_ID;
import static com.android.server.am.TaskRecordProto.STACK_ID;

import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.MAX_VALUE;


import android.annotation.IntDef;
import android.annotation.IntDef;
@@ -1686,11 +1684,19 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont
        // so that the user can not render the task too small to manipulate. We don't need
        // so that the user can not render the task too small to manipulate. We don't need
        // to do this for the pinned stack as the bounds are controlled by the system.
        // to do this for the pinned stack as the bounds are controlled by the system.
        if (!inPinnedWindowingMode()) {
        if (!inPinnedWindowingMode()) {
            final int defaultMinSizeDp =
                    mService.mStackSupervisor.mDefaultMinSizeOfResizeableTaskDp;
            final ActivityDisplay display =
                    mService.mStackSupervisor.getActivityDisplay(mStack.mDisplayId);
            final float density =
                    (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
            final int defaultMinSize = (int) (defaultMinSizeDp * density);

            if (minWidth == INVALID_MIN_SIZE) {
            if (minWidth == INVALID_MIN_SIZE) {
                minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
                minWidth = defaultMinSize;
            }
            }
            if (minHeight == INVALID_MIN_SIZE) {
            if (minHeight == INVALID_MIN_SIZE) {
                minHeight = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
                minHeight = defaultMinSize;
            }
            }
        }
        }
        final boolean adjustWidth = minWidth > bounds.width();
        final boolean adjustWidth = minWidth > bounds.width();
Loading