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

Commit 7d701174 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Protect against NPE for ActivityRecords without a stack.

A previous change allowed us to remove stack that no longer contained
any task. This was causing some NPE when an ActivityRecord.Token or
some other cached ActivityRecord later gets converted back to an
ActivityRecord and we try to access its stack.

Bug: 19552874
Change-Id: Ie9454bbce56591b337f97af40f8c00b8597becdf
parent 04f4d6bb
Loading
Loading
Loading
Loading
+26 −22
Original line number Diff line number Diff line
@@ -1757,7 +1757,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
            case ENTER_ANIMATION_COMPLETE_MSG: {
                synchronized (ActivityManagerService.this) {
                    ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
                    ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
                    if (r != null && r.app != null && r.app.thread != null) {
                        try {
                            r.app.thread.scheduleEnterAnimationComplete(r.appToken);
@@ -3955,11 +3955,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                return;
            }
            ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(
                    mHeavyWeightProcess.activities);
            ArrayList<ActivityRecord> activities = new ArrayList<>(mHeavyWeightProcess.activities);
            for (int i = 0; i < activities.size(); i++) {
                ActivityRecord r = activities.get(i);
                if (!r.finishing) {
                if (!r.finishing && r.isInStackLocked()) {
                    r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
                            null, "finish-heavy", true);
                }
@@ -4086,7 +4085,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            final long origId = Binder.clearCallingIdentity();
            try {
                ActivityRecord r = ActivityRecord.isInStackLocked(token);
                if (r.task == null || r.task.stack == null) {
                if (r == null) {
                    return false;
                }
                return r.task.stack.safelyDestroyActivityLocked(r, "app-req");
@@ -7797,20 +7796,19 @@ public final class ActivityManagerService extends ActivityManagerNative
                    android.Manifest.permission.GET_DETAILED_TASKS)
                    == PackageManager.PERMISSION_GRANTED;
            final int N = mRecentTasks.size();
            ArrayList<ActivityManager.RecentTaskInfo> res
                    = new ArrayList<ActivityManager.RecentTaskInfo>(
                            maxNum < N ? maxNum : N);
            final int recentsCount = mRecentTasks.size();
            ArrayList<ActivityManager.RecentTaskInfo> res =
                    new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
            final Set<Integer> includedUsers;
            if (includeProfiles) {
                includedUsers = getProfileIdsLocked(userId);
            } else {
                includedUsers = new HashSet<Integer>();
                includedUsers = new HashSet<>();
            }
            includedUsers.add(Integer.valueOf(userId));
            for (int i=0; i<N && maxNum > 0; i++) {
            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Only add calling user or related users recent tasks
                if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
@@ -8292,7 +8290,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            if (parentActivityToken == null) {
                throw new IllegalArgumentException("parent token must not be null");
            }
            ActivityRecord r = ActivityRecord.forToken(parentActivityToken);
            ActivityRecord r = ActivityRecord.forTokenLocked(parentActivityToken);
            if (r == null) {
                return null;
            }
@@ -8494,7 +8492,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        long ident = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                final ActivityRecord r = ActivityRecord.forToken(token);
                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                if (r == null) {
                    return;
                }
@@ -16573,8 +16571,8 @@ public final class ActivityManagerService extends ActivityManagerNative
    @Override
    public boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
        synchronized (this) {
            ActivityRecord srec = ActivityRecord.forToken(token);
            if (srec.task != null && srec.task.stack != null) {
            ActivityRecord srec = ActivityRecord.forTokenLocked(token);
            if (srec != null) {
                return srec.task.stack.shouldUpRecreateTaskLocked(srec, destAffinity);
            }
        }
@@ -16585,16 +16583,19 @@ public final class ActivityManagerService extends ActivityManagerNative
            Intent resultData) {
        synchronized (this) {
            final ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                return stack.navigateUpToLocked(token, destIntent, resultCode, resultData);
            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
            if (r != null) {
                return r.task.stack.navigateUpToLocked(r, destIntent, resultCode, resultData);
            }
            return false;
        }
    }
    public int getLaunchedFromUid(IBinder activityToken) {
        ActivityRecord srec = ActivityRecord.forToken(activityToken);
        ActivityRecord srec;
        synchronized (this) {
            srec = ActivityRecord.forTokenLocked(activityToken);
        }
        if (srec == null) {
            return -1;
        }
@@ -16602,7 +16603,10 @@ public final class ActivityManagerService extends ActivityManagerNative
    }
    public String getLaunchedFromPackage(IBinder activityToken) {
        ActivityRecord srec = ActivityRecord.forToken(activityToken);
        ActivityRecord srec;
        synchronized (this) {
            srec = ActivityRecord.forTokenLocked(activityToken);
        }
        if (srec == null) {
            return null;
        }
+134 −113
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.am;

import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
@@ -319,45 +320,84 @@ final class ActivityRecord {
    }

    static class Token extends IApplicationToken.Stub {
        final WeakReference<ActivityRecord> weakActivity;
        private final WeakReference<ActivityRecord> weakActivity;
        private final ActivityManagerService mService;

        Token(ActivityRecord activity) {
        Token(ActivityRecord activity, ActivityManagerService service) {
            weakActivity = new WeakReference<>(activity);
            mService = service;
        }

        @Override public void windowsDrawn() {
            ActivityRecord activity = weakActivity.get();
            if (activity != null) {
                activity.windowsDrawn();
        @Override
        public void windowsDrawn() {
            synchronized (mService) {
                ActivityRecord r = tokenToActivityRecordLocked(this);
                if (r != null) {
                    r.windowsDrawnLocked();
                }
            }
        }

        @Override public void windowsVisible() {
            ActivityRecord activity = weakActivity.get();
            if (activity != null) {
                activity.windowsVisible();
        @Override
        public void windowsVisible() {
            synchronized (mService) {
                ActivityRecord r = tokenToActivityRecordLocked(this);
                if (r != null) {
                    r.windowsVisibleLocked();
                }
            }
        }

        @Override public void windowsGone() {
            ActivityRecord activity = weakActivity.get();
            if (activity != null) {
                activity.windowsGone();
        @Override
        public void windowsGone() {
            synchronized (mService) {
                ActivityRecord r = tokenToActivityRecordLocked(this);
                if (r != null) {
                    if (DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + r);
                    r.nowVisible = false;
                    return;
                }
            }

        @Override public boolean keyDispatchingTimedOut(String reason) {
            ActivityRecord activity = weakActivity.get();
            return activity != null && activity.keyDispatchingTimedOut(reason);
        }

        @Override public long getKeyDispatchingTimeout() {
            ActivityRecord activity = weakActivity.get();
            if (activity != null) {
                return activity.getKeyDispatchingTimeout();
        @Override
        public boolean keyDispatchingTimedOut(String reason) {
            ActivityRecord r;
            ActivityRecord anrActivity;
            ProcessRecord anrApp;
            synchronized (mService) {
                r = tokenToActivityRecordLocked(this);
                if (r == null) {
                    return false;
                }
                anrActivity = r.getWaitingHistoryRecordLocked();
                anrApp = r != null ? r.app : null;
            }
            return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
        }

        @Override
        public long getKeyDispatchingTimeout() {
            synchronized (mService) {
                ActivityRecord r = tokenToActivityRecordLocked(this);
                if (r == null) {
                    return 0;
                }
                r = r.getWaitingHistoryRecordLocked();
                return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
            }
        }

        private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
            if (token == null) {
                return null;
            }
            ActivityRecord r = token.weakActivity.get();
            if (r == null || r.task == null || r.task.stack == null) {
                return null;
            }
            return r;
        }

        @Override
        public String toString() {
@@ -371,9 +411,9 @@ final class ActivityRecord {
        }
    }

    static ActivityRecord forToken(IBinder token) {
    static ActivityRecord forTokenLocked(IBinder token) {
        try {
            return token != null ? ((Token)token).weakActivity.get() : null;
            return Token.tokenToActivityRecordLocked((Token)token);
        } catch (ClassCastException e) {
            Slog.w(TAG, "Bad activity token: " + token, e);
            return null;
@@ -391,7 +431,7 @@ final class ActivityRecord {
            boolean _componentSpecified, ActivityStackSupervisor supervisor,
            ActivityContainer container, Bundle options) {
        service = _service;
        appToken = new Token(this);
        appToken = new Token(this, service);
        info = aInfo;
        launchedFromUid = _launchedFromUid;
        launchedFromPackage = _launchedFromPackage;
@@ -528,13 +568,8 @@ final class ActivityRecord {
    }

    void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
        if (task != null && task.removeActivity(this)) {
            if (task != newTask) {
        if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) {
            task.stack.removeTask(task, "setTask");
            } else {
                Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
                        (newTask == null ? null : newTask.stack));
            }
        }
        task = newTask;
        setTaskToAffiliateWith(taskToAffiliateWith);
@@ -580,6 +615,10 @@ final class ActivityRecord {
        return inHistory;
    }

    boolean isInStackLocked() {
        return task != null && task.stack != null && task.stack.isInStackLocked(this) != null;
    }

    boolean isHomeActivity() {
        return mActivityType == HOME_ACTIVITY_TYPE;
    }
@@ -599,9 +638,10 @@ final class ActivityRecord {
                        (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
    }

    void makeFinishing() {
    void makeFinishingLocked() {
        if (!finishing) {
            if (this == task.stack.getVisibleBehindActivity()) {
            if (task != null && task.stack != null
                    && this == task.stack.getVisibleBehindActivity()) {
                // A finishing activity should not remain as visible in the background
                mStackSupervisor.requestVisibleBehindLocked(this, false);
            }
@@ -670,7 +710,8 @@ final class ActivityRecord {
        // stack.
        final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
        boolean unsent = true;
        if ((state == ActivityState.RESUMED || (service.isSleeping()
        if ((state == ActivityState.RESUMED
                || (service.isSleeping() && task.stack != null
                    && task.stack.topRunningActivityLocked(null) == this))
                && app != null && app.thread != null) {
            try {
@@ -842,19 +883,27 @@ final class ActivityRecord {
    }

    boolean continueLaunchTickingLocked() {
        if (launchTickTime != 0) {
        if (launchTickTime == 0) {
            return false;
        }

        final ActivityStack stack = task.stack;
        if (stack == null) {
            return false;
        }

        Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
        stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
        stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
        return true;
    }
        return false;
    }

    void finishLaunchTickingLocked() {
        launchTickTime = 0;
        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
        final ActivityStack stack = task.stack;
        if (stack != null) {
            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
        }
    }

    // IApplicationToken
@@ -885,8 +934,8 @@ final class ActivityRecord {
        if (displayStartTime != 0) {
            reportLaunchTimeLocked(curTime);
        }
        if (fullyDrawnStartTime != 0) {
        final ActivityStack stack = task.stack;
        if (fullyDrawnStartTime != 0 && stack != null) {
            final long thisTime = curTime - fullyDrawnStartTime;
            final long totalTime = stack.mFullyDrawnStartTime != 0
                    ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
@@ -911,13 +960,16 @@ final class ActivityRecord {
            if (totalTime > 0) {
                //service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
            }
            fullyDrawnStartTime = 0;
            stack.mFullyDrawnStartTime = 0;
        }
        fullyDrawnStartTime = 0;
    }

    private void reportLaunchTimeLocked(final long curTime) {
        final ActivityStack stack = task.stack;
        if (stack == null) {
            return;
        }
        final long thisTime = curTime - displayStartTime;
        final long totalTime = stack.mLaunchStartTime != 0
                ? (curTime - stack.mLaunchStartTime) : thisTime;
@@ -947,8 +999,7 @@ final class ActivityRecord {
        stack.mLaunchStartTime = 0;
    }

    public void windowsDrawn() {
        synchronized(service) {
    void windowsDrawnLocked() {
        if (displayStartTime != 0) {
            reportLaunchTimeLocked(SystemClock.uptimeMillis());
        }
@@ -959,32 +1010,26 @@ final class ActivityRecord {
            task.hasBeenVisible = true;
        }
    }
    }

    public void windowsVisible() {
        synchronized(service) {
    void windowsVisibleLocked() {
        mStackSupervisor.reportActivityVisibleLocked(this);
            if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG, "windowsVisible(): " + this);
        if (DEBUG_SWITCH) Log.v(TAG, "windowsVisibleLocked(): " + this);
        if (!nowVisible) {
            nowVisible = true;
            lastVisibleTime = SystemClock.uptimeMillis();
            if (!idle) {
                    // Instead of doing the full stop routine here, let's just
                    // hide any activities we now can, and let them stop when
                    // the normal idle happens.
                // Instead of doing the full stop routine here, let's just hide any activities
                // we now can, and let them stop when the normal idle happens.
                mStackSupervisor.processStoppingActivitiesLocked(false);
            } else {
                    // If this activity was already idle, then we now need to
                    // make sure we perform the full stop of any activities
                    // that are waiting to do so.  This is because we won't
                    // do that while they are still waiting for this one to
                    // become visible.
                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
                    if (N > 0) {
                        for (int i=0; i<N; i++) {
                // If this activity was already idle, then we now need to make sure we perform
                // the full stop of any activities that are waiting to do so. This is because
                // we won't do that while they are still waiting for this one to become visible.
                final int size = mStackSupervisor.mWaitingVisibleActivities.size();
                if (size > 0) {
                    for (int i = 0; i < size; i++) {
                        ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG,
                                    "Was waiting for visible: " + r);
                        if (DEBUG_SWITCH) Log.v(TAG, "Was waiting for visible: " + r);
                    }
                    mStackSupervisor.mWaitingVisibleActivities.clear();
                    mStackSupervisor.scheduleIdleLocked();
@@ -993,14 +1038,8 @@ final class ActivityRecord {
            service.scheduleAppGcsLocked();
        }
    }
    }

    public void windowsGone() {
        if (ActivityManagerService.DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + this);
        nowVisible = false;
    }

    private ActivityRecord getWaitingHistoryRecordLocked() {
    ActivityRecord getWaitingHistoryRecordLocked() {
        // First find the real culprit...  if we are waiting
        // for another app to start, then we have paused dispatching
        // for this activity.
@@ -1021,24 +1060,6 @@ final class ActivityRecord {
        return r;
    }

    public boolean keyDispatchingTimedOut(String reason) {
        ActivityRecord r;
        ProcessRecord anrApp;
        synchronized(service) {
            r = getWaitingHistoryRecordLocked();
            anrApp = r != null ? r.app : null;
        }
        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
    }

    /** Returns the key dispatching timeout for this application token. */
    public long getKeyDispatchingTimeout() {
        synchronized(service) {
            ActivityRecord r = getWaitingHistoryRecordLocked();
            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
        }
    }

    /**
     * This method will return true if the activity is either visible, is becoming visible, is
     * currently pausing, or is resumed.
@@ -1066,14 +1087,14 @@ final class ActivityRecord {
    }

    static void activityResumedLocked(IBinder token) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
        r.icicle = null;
        r.haveState = false;
    }

    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r == null) {
            return INVALID_TASK_ID;
        }
@@ -1086,7 +1107,7 @@ final class ActivityRecord {
    }

    static ActivityRecord isInStackLocked(IBinder token) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        return (r != null) ? r.task.stack.isInStackLocked(r) : null;
    }

+9 −9
Original line number Diff line number Diff line
@@ -461,7 +461,7 @@ final class ActivityStack {
    }

    ActivityRecord isInStackLocked(IBinder token) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        return isInStackLocked(r);
    }

@@ -470,7 +470,8 @@ final class ActivityStack {
            return null;
        }
        final TaskRecord task = r.task;
        if (task != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
        if (task != null && task.stack != null
                && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
            if (task.stack != this) Slog.w(TAG,
                    "Illegal state! task does not point to stack it is in.");
            return r;
@@ -2795,7 +2796,7 @@ final class ActivityStack {
            return false;
        }

        r.makeFinishing();
        r.makeFinishingLocked();
        final TaskRecord task = r.task;
        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                r.userId, System.identityHashCode(r),
@@ -2898,7 +2899,7 @@ final class ActivityStack {
                || prevState == ActivityState.INITIALIZING) {
            // If this activity is already stopped, we can just finish
            // it right now.
            r.makeFinishing();
            r.makeFinishingLocked();
            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
            if (activityRemoved) {
                mStackSupervisor.resumeTopActivitiesLocked();
@@ -2974,9 +2975,8 @@ final class ActivityStack {
        return false;
    }

    final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
            Intent resultData) {
        final ActivityRecord srec = ActivityRecord.forToken(token);
        final TaskRecord task = srec.task;
        final ArrayList<ActivityRecord> activities = task.mActivities;
        final int start = activities.indexOf(srec);
@@ -3123,7 +3123,7 @@ final class ActivityStack {
    private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
        mStackSupervisor.removeChildActivityContainers(r);
        finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
        r.makeFinishing();
        r.makeFinishingLocked();
        if (DEBUG_ADD_REMOVE) {
            RuntimeException here = new RuntimeException("here");
            here.fillInStackTrace();
@@ -3364,7 +3364,7 @@ final class ActivityStack {
    final void activityDestroyedLocked(IBinder token, String reason) {
        final long origId = Binder.clearCallingIdentity();
        try {
            ActivityRecord r = ActivityRecord.forToken(token);
            ActivityRecord r = ActivityRecord.forTokenLocked(token);
            if (r != null) {
                mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
            }
@@ -3945,7 +3945,7 @@ final class ActivityStack {
                }
            }
        }
        final ActivityRecord r = ActivityRecord.forToken(token);
        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r == null) {
            return false;
        }
+31 −13

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -275,8 +275,10 @@ final class PendingIntentRecord extends IIntentSender.Stub {
                        }
                        break;
                    case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
                        if (key.activity.task.stack != null) {
                            key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
                                    key.who, key.requestCode, code, finalIntent);
                        }
                        break;
                    case ActivityManager.INTENT_SENDER_BROADCAST:
                        try {
Loading