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

Commit 2bd4bc25 authored by Weilin Xu's avatar Weilin Xu
Browse files

Set bcradio HAL tuner callback when sessions exist

Set broadcast radio HAL tuner callback for a radio tuner only when
there is at least one active tuner session, unset tuner callbacks
otherwise. This allows that radio tuner chip powers on only when it
is used in app, which reduces power consumption.

Bug: 327686652
Test: atest com.android.server.broadcastradio.aidl
Change-Id: Ie1fd55e2ad8983c59e4cf5ad711dd88fed84e4fd
parent 0d5f65a7
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -87,13 +87,6 @@ public final class RadioModuleTest {
                .that(mRadioModule.getProperties()).isEqualTo(TEST_MODULE_PROPERTIES);
    }

    @Test
    public void setInternalHalCallback_callbackSetInHal() throws Exception {
        mRadioModule.setInternalHalCallback();

        verify(mBroadcastRadioMock).setTunerCallback(any());
    }

    @Test
    public void getImage_withValidIdFromRadioModule() {
        int imageId = 1;
+68 −60
Original line number Diff line number Diff line
@@ -192,66 +192,6 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
            mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
            return null;
        }).when(mBroadcastRadioMock).setTunerCallback(any());
        mRadioModule.setInternalHalCallback();

        doAnswer(invocation -> {
            android.hardware.broadcastradio.ProgramSelector halSel =
                    (android.hardware.broadcastradio.ProgramSelector) invocation.getArguments()[0];
            mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo(halSel, SIGNAL_QUALITY);
            if (halSel.primaryId.type != IdentifierType.AMFM_FREQUENCY_KHZ) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).tune(any());

        doAnswer(invocation -> {
            if ((boolean) invocation.getArguments()[0]) {
                mHalCurrentInfo.selector.primaryId.value += AM_FM_FREQUENCY_SPACING;
            } else {
                mHalCurrentInfo.selector.primaryId.value -= AM_FM_FREQUENCY_SPACING;
            }
            mHalCurrentInfo.logicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalCurrentInfo.physicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).step(anyBoolean());

        doAnswer(invocation -> {
            if (mHalCurrentInfo == null) {
                android.hardware.broadcastradio.ProgramSelector placeHolderSelector =
                        AidlTestUtils.makeHalFmSelector(/* freq= */ 97300);

                mHalTunerCallback.onTuneFailed(Result.TIMEOUT, placeHolderSelector);
                return Result.OK;
            }
            mHalCurrentInfo.selector.primaryId.value = getSeekFrequency(
                    mHalCurrentInfo.selector.primaryId.value,
                    !(boolean) invocation.getArguments()[0]);
            mHalCurrentInfo.logicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalCurrentInfo.physicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());

        doReturn(null).when(mBroadcastRadioMock).getImage(anyInt());

        doAnswer(invocation -> {
            int configFlag = (int) invocation.getArguments()[0];
            if (configFlag == UNSUPPORTED_CONFIG_FLAG) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            return mHalConfigMap.getOrDefault(configFlag, false);
        }).when(mBroadcastRadioMock).isConfigFlagSet(anyInt());

        doAnswer(invocation -> {
            int configFlag = (int) invocation.getArguments()[0];
            if (configFlag == UNSUPPORTED_CONFIG_FLAG) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            mHalConfigMap.put(configFlag, (boolean) invocation.getArguments()[1]);
            return null;
        }).when(mBroadcastRadioMock).setConfigFlag(anyInt(), anyBoolean());
    }

    @After
@@ -330,6 +270,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {

        expect.withMessage("Close state of broadcast radio service session")
                .that(mTunerSessions[0].isClosed()).isTrue();
        verify(mBroadcastRadioMock).unsetTunerCallback();
    }

    @Test
@@ -351,6 +292,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
                        .that(mTunerSessions[index].isClosed()).isFalse();
            }
        }
        verify(mBroadcastRadioMock, never()).unsetTunerCallback();
    }

    @Test
@@ -378,6 +320,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
            expect.withMessage("Close state of broadcast radio service session of index %s", index)
                    .that(mTunerSessions[index].isClosed()).isTrue();
        }
        verify(mBroadcastRadioMock).unsetTunerCallback();
    }

    @Test
@@ -1295,6 +1238,71 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
            mAidlTunerCallbackMocks[index] = mock(android.hardware.radio.ITunerCallback.class);
            mTunerSessions[index] = mRadioModule.openSession(mAidlTunerCallbackMocks[index]);
        }
        setupMockedHalTunerSession();
    }

    private void setupMockedHalTunerSession() throws Exception {
        expect.withMessage("Registered HAL tuner callback").that(mHalTunerCallback)
                .isNotNull();

        doAnswer(invocation -> {
            android.hardware.broadcastradio.ProgramSelector halSel =
                    (android.hardware.broadcastradio.ProgramSelector) invocation.getArguments()[0];
            mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo(halSel, SIGNAL_QUALITY);
            if (halSel.primaryId.type != IdentifierType.AMFM_FREQUENCY_KHZ) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).tune(any());

        doAnswer(invocation -> {
            if ((boolean) invocation.getArguments()[0]) {
                mHalCurrentInfo.selector.primaryId.value += AM_FM_FREQUENCY_SPACING;
            } else {
                mHalCurrentInfo.selector.primaryId.value -= AM_FM_FREQUENCY_SPACING;
            }
            mHalCurrentInfo.logicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalCurrentInfo.physicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).step(anyBoolean());

        doAnswer(invocation -> {
            if (mHalCurrentInfo == null) {
                android.hardware.broadcastradio.ProgramSelector placeHolderSelector =
                        AidlTestUtils.makeHalFmSelector(/* freq= */ 97300);

                mHalTunerCallback.onTuneFailed(Result.TIMEOUT, placeHolderSelector);
                return Result.OK;
            }
            mHalCurrentInfo.selector.primaryId.value = getSeekFrequency(
                    mHalCurrentInfo.selector.primaryId.value,
                    !(boolean) invocation.getArguments()[0]);
            mHalCurrentInfo.logicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalCurrentInfo.physicallyTunedTo = mHalCurrentInfo.selector.primaryId;
            mHalTunerCallback.onCurrentProgramInfoChanged(mHalCurrentInfo);
            return Result.OK;
        }).when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());

        doReturn(null).when(mBroadcastRadioMock).getImage(anyInt());

        doAnswer(invocation -> {
            int configFlag = (int) invocation.getArguments()[0];
            if (configFlag == UNSUPPORTED_CONFIG_FLAG) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            return mHalConfigMap.getOrDefault(configFlag, false);
        }).when(mBroadcastRadioMock).isConfigFlagSet(anyInt());

        doAnswer(invocation -> {
            int configFlag = (int) invocation.getArguments()[0];
            if (configFlag == UNSUPPORTED_CONFIG_FLAG) {
                throw new ServiceSpecificException(Result.NOT_SUPPORTED);
            }
            mHalConfigMap.put(configFlag, (boolean) invocation.getArguments()[1]);
            return null;
        }).when(mBroadcastRadioMock).setConfigFlag(anyInt(), anyBoolean());
    }

    private long getSeekFrequency(long currentFrequency, boolean seekDown) {
+0 −7
Original line number Diff line number Diff line
@@ -82,13 +82,6 @@ public final class BroadcastRadioServiceImpl {
                    Slogf.w(TAG, "No module %s with id %d (HAL AIDL)", name, moduleId);
                    return;
                }
                try {
                    radioModule.setInternalHalCallback();
                } catch (RemoteException ex) {
                    Slogf.wtf(TAG, ex, "Broadcast radio module %s with id %d (HAL AIDL) "
                            + "cannot register HAL callback", name, moduleId);
                    return;
                }
                if (DEBUG) {
                    Slogf.d(TAG, "Loaded broadcast radio module %s with id %d (HAL AIDL)",
                            name, moduleId);
+12 −5
Original line number Diff line number Diff line
@@ -246,10 +246,6 @@ final class RadioModule {
        return mProperties;
    }

    void setInternalHalCallback() throws RemoteException {
        mService.setTunerCallback(mHalTunerCallback);
    }

    TunerSession openSession(android.hardware.radio.ITunerCallback userCb)
            throws RemoteException {
        mLogger.logRadioEvent("Open TunerSession");
@@ -257,10 +253,14 @@ final class RadioModule {
        Boolean antennaConnected;
        RadioManager.ProgramInfo currentProgramInfo;
        synchronized (mLock) {
            boolean isFirstTunerSession = mAidlTunerSessions.isEmpty();
            tunerSession = new TunerSession(this, mService, userCb);
            mAidlTunerSessions.add(tunerSession);
            antennaConnected = mAntennaConnected;
            currentProgramInfo = mCurrentProgramInfo;
            if (isFirstTunerSession) {
                mService.setTunerCallback(mHalTunerCallback);
            }
        }
        // Propagate state to new client.
        // Note: These callbacks are invoked while holding mLock to prevent race conditions
@@ -284,7 +284,6 @@ final class RadioModule {
        synchronized (mLock) {
            tunerSessions = new TunerSession[mAidlTunerSessions.size()];
            mAidlTunerSessions.toArray(tunerSessions);
            mAidlTunerSessions.clear();
        }

        for (TunerSession tunerSession : tunerSessions) {
@@ -402,6 +401,14 @@ final class RadioModule {
            mAidlTunerSessions.remove(tunerSession);
        }
        onTunerSessionProgramListFilterChanged(null);
        if (mAidlTunerSessions.isEmpty()) {
            try {
                mService.unsetTunerCallback();
            } catch (RemoteException ex) {
                Slogf.wtf(TAG, ex, "Failed to unregister HAL callback for module %d",
                        mProperties.getId());
            }
        }
    }

    // add to mHandler queue