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

Commit 3147037c authored by Joe Bolinger's avatar Joe Bolinger Committed by Android (Google) Code Review
Browse files

Merge "Prevent crash on death."

parents 83426076 a7a88c48
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -25,7 +25,11 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Allows clients (such as keyguard) to register for notifications on when biometric lockout
@@ -37,7 +41,8 @@ public class LockoutResetDispatcher implements IBinder.DeathRecipient {
    private static final String TAG = "LockoutResetTracker";

    private final Context mContext;
    private final ArrayList<ClientCallback> mClientCallbacks;
    @VisibleForTesting
    final List<ClientCallback> mClientCallbacks = new ArrayList<>();

    private static class ClientCallback {
        private static final long WAKELOCK_TIMEOUT_MS = 2000;
@@ -81,7 +86,6 @@ public class LockoutResetDispatcher implements IBinder.DeathRecipient {

    public LockoutResetDispatcher(Context context) {
        mContext = context;
        mClientCallbacks = new ArrayList<>();
    }

    public void addCallback(IBiometricServiceLockoutResetCallback callback, String opPackageName) {
@@ -106,11 +110,13 @@ public class LockoutResetDispatcher implements IBinder.DeathRecipient {
    @Override
    public void binderDied(IBinder who) {
        Slog.e(TAG, "Callback binder died: " + who);
        for (ClientCallback callback : mClientCallbacks) {
        final Iterator<ClientCallback> iterator = mClientCallbacks.iterator();
        while (iterator.hasNext()) {
            final ClientCallback callback = iterator.next();
            if (callback.mCallback.asBinder().equals(who)) {
                Slog.e(TAG, "Removing dead callback for: " + callback.mOpPackageName);
                callback.releaseWakelock();
                mClientCallbacks.remove(callback);
                iterator.remove();
            }
        }
    }
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.biometrics.sensors;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

@Presubmit
@SmallTest
public class LockoutResetDispatcherTest {

    @Rule
    public final MockitoRule mockito = MockitoJUnit.rule();

    @Rule
    public final TestableContext mContext = new TestableContext(
            InstrumentationRegistry.getInstrumentation().getTargetContext(), null);

    @Mock
    private IBinder mBinder;
    @Mock
    private IBiometricServiceLockoutResetCallback mCallback;

    private LockoutResetDispatcher mDispatcher;

    @Before
    public void setup() {
        when(mCallback.asBinder()).thenReturn(mBinder);
        mDispatcher = new LockoutResetDispatcher(mContext);
    }

    @Test
    public void linksToDeath() throws Exception {
        mDispatcher.addCallback(mCallback, "package");
        verify(mBinder).linkToDeath(eq(mDispatcher), anyInt());
    }

    @Test
    public void notifyLockoutReset() throws Exception {
        final int sensorId = 24;

        mDispatcher.addCallback(mCallback, "some.package");
        mDispatcher.notifyLockoutResetCallbacks(sensorId);

        final ArgumentCaptor<IRemoteCallback> captor =
                ArgumentCaptor.forClass(IRemoteCallback.class);
        verify(mCallback).onLockoutReset(eq(sensorId), captor.capture());
        captor.getValue().sendResult(new Bundle());
    }

    @Test
    public void releaseWakeLockOnDeath() {
        mDispatcher.addCallback(mCallback, "a.b.cee");
        mDispatcher.binderDied(mBinder);

        // would be better to check the wake lock
        // but this project lacks the extended mockito support to do it
        assertThat(mDispatcher.mClientCallbacks).isEmpty();
    }

    @Test
    public void releaseCorrectWakeLockOnDeath() {
        mDispatcher.addCallback(mCallback, "a.b");
        mDispatcher.binderDied(mock(IBinder.class));

        assertThat(mDispatcher.mClientCallbacks).hasSize(1);
    }
}