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

Commit 2393f6e2 authored by Kensuke Miyagi's avatar Kensuke Miyagi
Browse files

Add tuner resource inquery APIs

boolean Tuner#hasUnusedFrontend(int frontendType)
boolean Tuner#isLowestPriority(int frontendType)

Additionally, adding the following functions in
ITunerResourceManager.aidl to enable testing of the above APIs with
custom frontend resource map.

void storeFrontendResourceMap()
void clearFrontendResourceMap()
void restoreFrontendResourceMap()

Also adding dumpsys for TunerResourceManager.

Bug: 192010866
Test: android.media.tv.tuner.cts.TunerTest
Change-Id: I0b7eb6a3c13795f4101306faae0ec215d638b7cb
parent 130af6c5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -6051,6 +6051,8 @@ package android.media.tv.tuner {
    method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
    method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
    method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
    method public boolean hasUnusedFrontend(int);
    method public boolean isLowestPriority(int);
    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
    method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
    method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
+42 −0
Original line number Diff line number Diff line
@@ -449,6 +449,43 @@ public class Tuner implements AutoCloseable {
        mTunerResourceManager.updateClientPriority(mClientId, priority, niceValue);
    }

    /**
     * Checks if there is an unused frontend resource available.
     *
     * @param frontendType {@link android.media.tv.tuner.frontend.FrontendSettings.Type} for the
     * query to be done for.
     */
    public boolean hasUnusedFrontend(int frontendType) {
        return mTunerResourceManager.hasUnusedFrontend(frontendType);
    }

    /**
     * Checks if the calling Tuner object has the lowest priority as a client to
     * {@link TunerResourceManager}
     *
     * <p>The priority comparison is done against the current holders of the frontend resource.
     *
     * <p>The behavior of this function is independent of the availability of unused resources.
     *
     * <p>The function returns {@code true} in any of the following sceanrios:
     * <ul>
     * <li>The caller has the priority <= other clients</li>
     * <li>No one is holding the frontend resource of the specified type</li>
     * <li>The caller is the only one who is holding the resource</li>
     * <li>The frontend resource of the specified type does not exist</li>
     *
     * </ul>
     * @param frontendType {@link android.media.tv.tuner.frontend.FrontendSettings.Type} for the
     * query to be done for.
     *
     * @return {@code false} only if someone else with strictly lower priority is holding the
     *         resourece.
     *         {@code true} otherwise.
     */
    public boolean isLowestPriority(int frontendType) {
        return mTunerResourceManager.isLowestPriority(mClientId, frontendType);
    }

    private long mNativeContext; // used by native jMediaTuner

    /**
@@ -1615,4 +1652,9 @@ public class Tuner implements AutoCloseable {
        }
        mLnb = null;
    }

    /** @hide */
    public int getClientId() {
        return mClientId;
    }
}
+90 −0
Original line number Diff line number Diff line
@@ -178,6 +178,96 @@ public class TunerResourceManager {
        return result;
    }

    /**
     * Checks if there is an unused frontend resource available.
     *
     * @param frontendType The frontend type for the query to be done for.
     */
    public boolean hasUnusedFrontend(int frontendType) {
        boolean result = false;
        try {
            result = mService.hasUnusedFrontend(frontendType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result;
    }

    /**
     * Checks if the client has the lowest priority among the clients that are holding
     * the frontend resource of the specified type.
     *
     * <p> When this function returns false, it means that there is at least one client with the
     * strictly lower priority (than clientId) that is reclaimable by the system.
     *
     * @param clientId The client ID to be checked the priority for.
     * @param frontendType The specific frontend type to be checked for.
     *
     * @return false if there is another client holding the frontend resource of the specified type
     * that can be reclaimed. Otherwise true.
     */
    public boolean isLowestPriority(int clientId, int frontendType) {
        boolean result = false;
        try {
            result = mService.isLowestPriority(clientId, frontendType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return result;
    }

    /**
     * Stores the frontend resource map if it was stored before.
     *
     * <p>This API is only for testing purpose and should be used in pair with
     * restoreResourceMap(), which allows testing of {@link Tuner} APIs
     * that behave differently based on different sets of resource map.
     *
     * @param resourceType The resource type to store the map for.
     */
    public void storeResourceMap(int resourceType) {
        try {
            mService.storeResourceMap(resourceType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Clears the frontend resource map.
     *
     * <p>This API is only for testing purpose and should be called right after
     * storeResourceMap(), so TRMService#removeFrontendResource() does not
     * get called in TRMService#setFrontendInfoListInternal() for custom frontend
     * resource map creation.
     *
     * @param resourceType The resource type to clear the map for.
     */
    public void clearResourceMap(int resourceType) {
        try {
            mService.clearResourceMap(resourceType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Restores Frontend resource map for the later restore.
     *
     * <p>This API is only for testing purpose and should be used in pair with
     * storeResourceMap(), which allows testing of {@link Tuner} APIs
     * that behave differently based on different sets of resource map.
     *
     * @param resourceType The resource type to restore the map for.
     */
    public void restoreResourceMap(int resourceType) {
        try {
            mService.restoreResourceMap(resourceType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Updates the current TRM of the TunerHAL Frontend information.
     *
+58 −0
Original line number Diff line number Diff line
@@ -82,6 +82,30 @@ interface ITunerResourceManager {
     */
    boolean updateClientPriority(in int clientId, in int priority, in int niceValue);

    /*
     * Checks if there is any unused frontend resource of the specified type.
     *
     * @param frontendType the specific type of frontend resource to be checked for.
     *
     * @return true if there is any unused resource of the specified type.
     */
    boolean hasUnusedFrontend(in int frontendType);

    /*
     * Checks if the client has the lowest priority among the clients that are holding
     * the frontend resource of the specified type.
     *
     * <p> When this function returns false, it means that there is at least one client with the
     * strictly lower priority (than clientId) that is reclaimable by the system.
     *
     * @param clientId The client ID to be checked the priority for.
     * @param frontendType The specific frontend type to be checked for.
     *
     * @return false if there is another client holding the frontend resource of the specified type
     * that can be reclaimed. Otherwise true.
     */
    boolean isLowestPriority(in int clientId, in int frontendType);

    /*
     * Updates the available Frontend resources information on the current device.
     *
@@ -354,4 +378,38 @@ interface ITunerResourceManager {
     */
    boolean isHigherPriority(in ResourceClientProfile challengerProfile,
            in ResourceClientProfile holderProfile);

    /*
     * Stores Frontend resource map for the later restore.
     *
     * <p>This is API is only for testing purpose and should be used in pair with
     * restoreResourceMap(), which allows testing of {@link Tuner} APIs
     * that behave differently based on different sets of resource map.
     *
     * @param resourceType The resource type to store the map for.
     */
    void storeResourceMap(in int resourceType);

    /*
     * Clears the frontend resource map.
     *
     * <p>This is API is only for testing purpose and should be called right after
     * storeResourceMap(), so TRMService#removeFrontendResource() does not
     * get called in TRMService#setFrontendInfoListInternal() for custom frontend
     * resource map creation.
     *
     * @param resourceType The resource type to clear the map for.
     */
    void clearResourceMap(in int resourceType);

    /*
     * Restores Frontend resource map if it was stored before.
     *
     * <p>This is API is only for testing purpose and should be used in pair with
     * storeResourceMap(), which allows testing of {@link Tuner} APIs
     * that behave differently based on different sets of resource map.
     *
     * @param resourceType The resource type to restore the map for.
     */
    void restoreResourceMap(in int resourceType);
}
+201 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;

@@ -44,6 +45,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -68,6 +71,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde

    // Map of the current available frontend resources
    private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
    // Backup Map of the current available frontend resources
    private Map<Integer, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
    // Map of the current available lnb resources
    private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
    // Map of the current available Cas resources
@@ -173,6 +178,27 @@ public class TunerResourceManagerService extends SystemService implements IBinde
            }
        }

        @Override
        public boolean hasUnusedFrontend(int frontendType) {
            enforceTrmAccessPermission("hasUnusedFrontend");
            synchronized (mLock) {
                return hasUnusedFrontendInternal(frontendType);
            }
        }

        @Override
        public boolean isLowestPriority(int clientId, int frontendType)
                throws RemoteException {
            enforceTrmAccessPermission("isLowestPriority");
            synchronized (mLock) {
                if (!checkClientExists(clientId)) {
                    throw new RemoteException("isLowestPriority called from unregistered client: "
                            + clientId);
                }
                return isLowestPriorityInternal(clientId, frontendType);
            }
        }

        @Override
        public void setFrontendInfoList(@NonNull TunerFrontendInfo[] infos) throws RemoteException {
            enforceTrmAccessPermission("setFrontendInfoList");
@@ -458,6 +484,104 @@ public class TunerResourceManagerService extends SystemService implements IBinde
                return isHigherPriorityInternal(challengerProfile, holderProfile);
            }
        }

        @Override
        public void storeResourceMap(int resourceType) {
            enforceTrmAccessPermission("storeResourceMap");
            synchronized (mLock) {
                storeResourceMapInternal(resourceType);
            }
        }

        @Override
        public void clearResourceMap(int resourceType) {
            enforceTrmAccessPermission("clearResourceMap");
            synchronized (mLock) {
                clearResourceMapInternal(resourceType);
            }
        }

        @Override
        public void restoreResourceMap(int resourceType) {
            enforceTrmAccessPermission("restoreResourceMap");
            synchronized (mLock) {
                restoreResourceMapInternal(resourceType);
            }
        }

        @Override
        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");

            synchronized (mLock) {
                if (mClientProfiles != null) {
                    pw.println("ClientProfiles:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, ClientProfile> entry : mClientProfiles.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mFrontendResources != null) {
                    pw.println("FrontendResources:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, FrontendResource> entry
                            : mFrontendResources.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mFrontendResourcesBackup != null) {
                    pw.println("FrontendResourcesBackUp:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, FrontendResource> entry
                            : mFrontendResourcesBackup.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mLnbResources != null) {
                    pw.println("LnbResources:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, LnbResource> entry : mLnbResources.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mCasResources != null) {
                    pw.println("CasResources:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, CasResource> entry : mCasResources.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mCiCamResources != null) {
                    pw.println("CiCamResources:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, CiCamResource> entry : mCiCamResources.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }

                if (mListeners != null) {
                    pw.println("Listners:");
                    pw.increaseIndent();
                    for (Map.Entry<Integer, ResourcesReclaimListenerRecord> entry
                            : mListeners.entrySet()) {
                        pw.println(entry.getKey() + " : " + entry.getValue());
                    }
                    pw.decreaseIndent();
                }
            }
        }

    }

    /**
@@ -552,6 +676,83 @@ public class TunerResourceManagerService extends SystemService implements IBinde
        return true;
    }


    protected boolean hasUnusedFrontendInternal(int frontendType) {
        for (FrontendResource fr : getFrontendResources().values()) {
            if (fr.getType() == frontendType && !fr.isInUse()) {
                return true;
            }
        }
        return false;
    }

    protected boolean isLowestPriorityInternal(int clientId, int frontendType)
            throws RemoteException {
        // Update the client priority
        ClientProfile requestClient = getClientProfile(clientId);
        if (requestClient == null) {
            return true;
        }
        clientPriorityUpdateOnRequest(requestClient);
        int clientPriority = requestClient.getPriority();

        // Check if there is another holder with lower priority
        for (FrontendResource fr : getFrontendResources().values()) {
            if (fr.getType() == frontendType && fr.isInUse()) {
                int priority = updateAndGetOwnerClientPriority(fr.getOwnerClientId());
                // Returns false only when the clientPriority is strictly greater
                // because false means that there is another reclaimable resource
                if (clientPriority > priority) {
                    return false;
                }
            }
        }
        return true;
    }

    protected void storeResourceMapInternal(int resourceType) {
        switch (resourceType) {
            case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
                if (mFrontendResources != null && mFrontendResources.size() > 0) {
                    mFrontendResourcesBackup.putAll(mFrontendResources);
                    mFrontendResources.clear();
                }
                break;
                // TODO: implement for other resource type when needed
            default:
                break;
        }
    }

    protected void clearResourceMapInternal(int resourceType) {
        switch (resourceType) {
            case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
                if (mFrontendResources != null) {
                    mFrontendResources.clear();
                }
                break;
                // TODO: implement for other resource type when needed
            default:
                break;
        }
    }

    protected void restoreResourceMapInternal(int resourceType) {
        switch (resourceType) {
            case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
                if (mFrontendResourcesBackup != null
                        && mFrontendResourcesBackup.size() > 0) {
                    mFrontendResources.clear();
                    mFrontendResources.putAll(mFrontendResourcesBackup);
                    mFrontendResourcesBackup.clear();
                }
                break;
                // TODO: implement for other resource type when needed
            default:
                break;
        }
    }

    @VisibleForTesting
    protected void setFrontendInfoListInternal(TunerFrontendInfo[] infos) {
        if (DEBUG) {