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

Commit 4f3c11f3 authored by Shubang Lu's avatar Shubang Lu
Browse files

CSAI: handle TvAdServiceInfo and callback

Bug: 319733468
Test: mmm
Change-Id: Iae777a8ca33c8d408ceea74da6a69e84c447fd46
parent 0cff75d3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package android.media.tv.ad;

import android.media.tv.ad.ITvAdClient;
import android.media.tv.ad.ITvAdManagerCallback;
import android.media.tv.ad.TvAdServiceInfo;
import android.view.Surface;

/**
@@ -24,6 +26,7 @@ import android.view.Surface;
 * @hide
 */
interface ITvAdManager {
    List<TvAdServiceInfo> getTvAdServiceList(int userId);
    void createSession(
            in ITvAdClient client, in String serviceId, in String type, int seq, int userId);
    void releaseSession(in IBinder sessionToken, int userId);
@@ -31,4 +34,7 @@ interface ITvAdManager {
    void setSurface(in IBinder sessionToken, in Surface surface, int userId);
    void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
            int userId);

    void registerCallback(in ITvAdManagerCallback callback, int userId);
    void unregisterCallback(in ITvAdManagerCallback callback, int userId);
}
+3 −0
Original line number Diff line number Diff line
@@ -21,4 +21,7 @@ package android.media.tv.ad;
 * @hide
 */
oneway interface ITvAdManagerCallback {
    void onAdServiceAdded(in String serviceId);
    void onAdServiceRemoved(in String serviceId);
    void onAdServiceUpdated(in String serviceId);
}
 No newline at end of file
+116 −0
Original line number Diff line number Diff line
@@ -121,6 +121,59 @@ public class TvAdManager {
            }

        };

        ITvAdManagerCallback managerCallback =
                new ITvAdManagerCallback.Stub() {
                    @Override
                    public void onAdServiceAdded(String serviceId) {
                        synchronized (mLock) {
                            for (TvAdServiceCallbackRecord record : mCallbackRecords) {
                                record.postAdServiceAdded(serviceId);
                            }
                        }
                    }

                    @Override
                    public void onAdServiceRemoved(String serviceId) {
                        synchronized (mLock) {
                            for (TvAdServiceCallbackRecord record : mCallbackRecords) {
                                record.postAdServiceRemoved(serviceId);
                            }
                        }
                    }

                    @Override
                    public void onAdServiceUpdated(String serviceId) {
                        synchronized (mLock) {
                            for (TvAdServiceCallbackRecord record : mCallbackRecords) {
                                record.postAdServiceUpdated(serviceId);
                            }
                        }
                    }
                };
        try {
            if (mService != null) {
                mService.registerCallback(managerCallback, mUserId);
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the complete list of TV AD service on the system.
     *
     * @return List of {@link TvAdServiceInfo} for each TV AD service that describes its meta
     * information.
     * @hide
     */
    @NonNull
    public List<TvAdServiceInfo> getTvAdServiceList() {
        try {
            return mService.getTvAdServiceList(mUserId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -499,6 +552,38 @@ public class TvAdManager {
     * @hide
     */
    public abstract static class TvAdServiceCallback {
        /**
         * This is called when a TV AD service is added to the system.
         *
         * <p>Normally it happens when the user installs a new TV AD service package that implements
         * {@link TvAdService} interface.
         *
         * @param serviceId The ID of the TV AD service.
         */
        public void onAdServiceAdded(@NonNull String serviceId) {
        }

        /**
         * This is called when a TV AD service is removed from the system.
         *
         * <p>Normally it happens when the user uninstalls the previously installed TV AD service
         * package.
         *
         * @param serviceId The ID of the TV AD service.
         */
        public void onAdServiceRemoved(@NonNull String serviceId) {
        }

        /**
         * This is called when a TV AD service is updated on the system.
         *
         * <p>Normally it happens when a previously installed TV AD service package is re-installed
         * or a newer version of the package exists becomes available/unavailable.
         *
         * @param serviceId The ID of the TV AD service.
         */
        public void onAdServiceUpdated(@NonNull String serviceId) {
        }

    }

@@ -550,5 +635,36 @@ public class TvAdManager {
            mCallback = callback;
            mExecutor = executor;
        }

        public TvAdServiceCallback getCallback() {
            return mCallback;
        }

        public void postAdServiceAdded(final String serviceId) {
            mExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    mCallback.onAdServiceAdded(serviceId);
                }
            });
        }

        public void postAdServiceRemoved(final String serviceId) {
            mExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    mCallback.onAdServiceRemoved(serviceId);
                }
            });
        }

        public void postAdServiceUpdated(final String serviceId) {
            mExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    mCallback.onAdServiceUpdated(serviceId);
                }
            });
        }
    }
}
+13 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
@@ -63,8 +64,7 @@ public final class TvAdServiceInfo implements Parcelable {
        if (context == null) {
            throw new IllegalArgumentException("context cannot be null.");
        }
        // TODO: use a constant
        Intent intent = new Intent("android.media.tv.ad.TvAdService").setComponent(component);
        Intent intent = new Intent(TvAdService.SERVICE_INTERFACE).setComponent(component);
        ResolveInfo resolveInfo = context.getPackageManager().resolveService(
                intent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
        if (resolveInfo == null) {
@@ -80,6 +80,7 @@ public final class TvAdServiceInfo implements Parcelable {

        mService = resolveInfo;
        mId = id;
        mTypes.addAll(types);
    }

    private TvAdServiceInfo(ResolveInfo service, String id, List<String> types) {
@@ -147,9 +148,8 @@ public final class TvAdServiceInfo implements Parcelable {
            ResolveInfo resolveInfo, Context context, List<String> types) {
        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
        PackageManager pm = context.getPackageManager();
        // TODO: use constant for the metadata
        try (XmlResourceParser parser =
                     serviceInfo.loadXmlMetaData(pm, "android.media.tv.ad.service")) {
                     serviceInfo.loadXmlMetaData(pm, TvAdService.SERVICE_META_DATA)) {
            if (parser == null) {
                throw new IllegalStateException(
                        "No " + "android.media.tv.ad.service"
@@ -171,7 +171,15 @@ public final class TvAdServiceInfo implements Parcelable {
                        + XML_START_TAG_NAME + " tag for " + serviceInfo.name);
            }

            // TODO: parse attributes
            TypedArray sa = resources.obtainAttributes(attrs,
                    com.android.internal.R.styleable.TvAdService);
            CharSequence[] textArr = sa.getTextArray(
                    com.android.internal.R.styleable.TvAdService_adServiceTypes);
            for (CharSequence cs : textArr) {
                types.add(cs.toString().toLowerCase());
            }

            sa.recycle();
        } catch (IOException | XmlPullParserException e) {
            throw new IllegalStateException(
                    "Failed reading meta-data for " + serviceInfo.packageName, e);
+229 −4
Original line number Diff line number Diff line
@@ -40,12 +40,14 @@ import android.media.tv.TvRecordingInfo;
import android.media.tv.TvTrackInfo;
import android.media.tv.ad.ITvAdClient;
import android.media.tv.ad.ITvAdManager;
import android.media.tv.ad.ITvAdManagerCallback;
import android.media.tv.ad.ITvAdService;
import android.media.tv.ad.ITvAdServiceCallback;
import android.media.tv.ad.ITvAdSession;
import android.media.tv.ad.ITvAdSessionCallback;
import android.media.tv.ad.TvAdService;
import android.media.tv.ad.TvAdServiceInfo;
import android.media.tv.flags.Flags;
import android.media.tv.interactive.AppLinkInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManager;
@@ -117,6 +119,8 @@ public class TvInteractiveAppManagerService extends SystemService {
    @GuardedBy("mLock")
    private boolean mGetServiceListCalled = false;
    @GuardedBy("mLock")
    private boolean mGetAdServiceListCalled = false;
    @GuardedBy("mLock")
    private boolean mGetAppLinkInfoListCalled = false;

    private final UserManager mUserManager;
@@ -262,6 +266,141 @@ public class TvInteractiveAppManagerService extends SystemService {
        userState.mIAppMap = iAppMap;
    }

    @GuardedBy("mLock")
    private void buildTvAdServiceListLocked(int userId, String[] updatedPackages) {
        if (!Flags.enableAdServiceFw()) {
            return;
        }
        UserState userState = getOrCreateUserStateLocked(userId);
        userState.mPackageSet.clear();

        if (DEBUG) {
            Slogf.d(TAG, "buildTvAdServiceListLocked");
        }
        PackageManager pm = mContext.getPackageManager();
        List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                new Intent(TvAdService.SERVICE_INTERFACE),
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                userId);
        List<TvAdServiceInfo> serviceList = new ArrayList<>();

        for (ResolveInfo ri : services) {
            ServiceInfo si = ri.serviceInfo;
            if (!android.Manifest.permission.BIND_TV_AD_SERVICE.equals(si.permission)) {
                Slog.w(TAG, "Skipping TV AD service " + si.name
                        + ": it does not require the permission "
                        + android.Manifest.permission.BIND_TV_AD_SERVICE);
                continue;
            }

            ComponentName component = new ComponentName(si.packageName, si.name);
            try {
                TvAdServiceInfo info = new TvAdServiceInfo(mContext, component);
                serviceList.add(info);
            } catch (Exception e) {
                Slogf.e(TAG, "failed to load TV AD service " + si.name, e);
                continue;
            }
            userState.mPackageSet.add(si.packageName);
        }

        // sort the service list by service id
        Collections.sort(serviceList, Comparator.comparing(TvAdServiceInfo::getId));
        Map<String, TvAdServiceState> adServiceMap = new HashMap<>();
        for (TvAdServiceInfo info : serviceList) {
            String serviceId = info.getId();
            if (DEBUG) {
                Slogf.d(TAG, "add " + serviceId);
            }
            TvAdServiceState adServiceState = userState.mAdServiceMap.get(serviceId);
            if (adServiceState == null) {
                adServiceState = new TvAdServiceState();
            }
            adServiceState.mInfo = info;
            adServiceState.mUid = getAdServiceUid(info);
            adServiceState.mComponentName = info.getComponent();
            adServiceMap.put(serviceId, adServiceState);
        }

        for (String serviceId : adServiceMap.keySet()) {
            if (!userState.mAdServiceMap.containsKey(serviceId)) {
                notifyAdServiceAddedLocked(userState, serviceId);
            } else if (updatedPackages != null) {
                // Notify the package updates
                ComponentName component = adServiceMap.get(serviceId).mInfo.getComponent();
                for (String updatedPackage : updatedPackages) {
                    if (component.getPackageName().equals(updatedPackage)) {
                        updateAdServiceConnectionLocked(component, userId);
                        notifyAdServiceUpdatedLocked(userState, serviceId);
                        break;
                    }
                }
            }
        }

        for (String serviceId : userState.mAdServiceMap.keySet()) {
            if (!adServiceMap.containsKey(serviceId)) {
                TvAdServiceInfo info = userState.mAdServiceMap.get(serviceId).mInfo;
                AdServiceState serviceState = userState.mAdServiceStateMap.get(info.getComponent());
                if (serviceState != null) {
                    abortPendingCreateAdSessionRequestsLocked(serviceState, serviceId, userId);
                }
                notifyAdServiceRemovedLocked(userState, serviceId);
            }
        }

        userState.mIAppMap.clear();
        userState.mAdServiceMap = adServiceMap;
    }

    @GuardedBy("mLock")
    private void notifyAdServiceAddedLocked(UserState userState, String serviceId) {
        if (DEBUG) {
            Slog.d(TAG, "notifyAdServiceAddedLocked(serviceId=" + serviceId + ")");
        }
        int n = userState.mAdCallbacks.beginBroadcast();
        for (int i = 0; i < n; ++i) {
            try {
                userState.mAdCallbacks.getBroadcastItem(i).onAdServiceAdded(serviceId);
            } catch (RemoteException e) {
                Slog.e(TAG, "failed to report added AD service to callback", e);
            }
        }
        userState.mAdCallbacks.finishBroadcast();
    }

    @GuardedBy("mLock")
    private void notifyAdServiceRemovedLocked(UserState userState, String serviceId) {
        if (DEBUG) {
            Slog.d(TAG, "notifyAdServiceRemovedLocked(serviceId=" + serviceId + ")");
        }
        int n = userState.mAdCallbacks.beginBroadcast();
        for (int i = 0; i < n; ++i) {
            try {
                userState.mAdCallbacks.getBroadcastItem(i).onAdServiceRemoved(serviceId);
            } catch (RemoteException e) {
                Slog.e(TAG, "failed to report removed AD service to callback", e);
            }
        }
        userState.mAdCallbacks.finishBroadcast();
    }

    @GuardedBy("mLock")
    private void notifyAdServiceUpdatedLocked(UserState userState, String serviceId) {
        if (DEBUG) {
            Slog.d(TAG, "notifyAdServiceUpdatedLocked(serviceId=" + serviceId + ")");
        }
        int n = userState.mAdCallbacks.beginBroadcast();
        for (int i = 0; i < n; ++i) {
            try {
                userState.mAdCallbacks.getBroadcastItem(i).onAdServiceUpdated(serviceId);
            } catch (RemoteException e) {
                Slog.e(TAG, "failed to report updated AD service to callback", e);
            }
        }
        userState.mAdCallbacks.finishBroadcast();
    }

    @GuardedBy("mLock")
    private void notifyInteractiveAppServiceAddedLocked(UserState userState, String iAppServiceId) {
        if (DEBUG) {
@@ -347,6 +486,16 @@ public class TvInteractiveAppManagerService extends SystemService {
        }
    }

    private int getAdServiceUid(TvAdServiceInfo info) {
        try {
            return getContext().getPackageManager().getApplicationInfo(
                    info.getServiceInfo().packageName, 0).uid;
        } catch (PackageManager.NameNotFoundException e) {
            Slogf.w(TAG, "Unable to get UID for  " + info, e);
            return Process.INVALID_UID;
        }
    }

    @Override
    public void onStart() {
        if (DEBUG) {
@@ -364,6 +513,7 @@ public class TvInteractiveAppManagerService extends SystemService {
            synchronized (mLock) {
                buildTvInteractiveAppServiceListLocked(mCurrentUserId, null);
                buildAppLinkInfoLocked(mCurrentUserId);
                buildTvAdServiceListLocked(mCurrentUserId, null);
            }
        }
    }
@@ -379,6 +529,14 @@ public class TvInteractiveAppManagerService extends SystemService {
                    }
                }
            }
            private void buildTvAdServiceList(String[] packages) {
                int userId = getChangingUserId();
                synchronized (mLock) {
                    if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
                        buildTvAdServiceListLocked(userId, packages);
                    }
                }
            }

            @Override
            public void onPackageUpdateFinished(String packageName, int uid) {
@@ -386,6 +544,7 @@ public class TvInteractiveAppManagerService extends SystemService {
                // This callback is invoked when the TV interactive App service is reinstalled.
                // In this case, isReplacing() always returns true.
                buildTvInteractiveAppServiceList(new String[] { packageName });
                buildTvAdServiceList(new String[] { packageName });
            }

            @Override
@@ -397,6 +556,7 @@ public class TvInteractiveAppManagerService extends SystemService {
                // available.
                if (isReplacing()) {
                    buildTvInteractiveAppServiceList(packages);
                    buildTvAdServiceList(packages);
                }
            }

@@ -410,6 +570,7 @@ public class TvInteractiveAppManagerService extends SystemService {
                }
                if (isReplacing()) {
                    buildTvInteractiveAppServiceList(packages);
                    buildTvAdServiceList(packages);
                }
            }

@@ -425,6 +586,7 @@ public class TvInteractiveAppManagerService extends SystemService {
                    return;
                }
                buildTvInteractiveAppServiceList(null);
                buildTvAdServiceList(null);
            }

            @Override
@@ -483,6 +645,7 @@ public class TvInteractiveAppManagerService extends SystemService {
            mCurrentUserId = userId;
            buildTvInteractiveAppServiceListLocked(userId, null);
            buildAppLinkInfoLocked(userId);
            buildTvAdServiceListLocked(userId, null);
        }
    }

@@ -569,6 +732,7 @@ public class TvInteractiveAppManagerService extends SystemService {
        mRunningProfiles.add(userId);
        buildTvInteractiveAppServiceListLocked(userId, null);
        buildAppLinkInfoLocked(userId);
        buildTvAdServiceListLocked(userId, null);
    }

    @GuardedBy("mLock")
@@ -749,6 +913,29 @@ public class TvInteractiveAppManagerService extends SystemService {
    }
    private final class TvAdBinderService extends ITvAdManager.Stub {

        @Override
        public List<TvAdServiceInfo> getTvAdServiceList(int userId) {
            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, "getTvAdServiceList");
            final long identity = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    if (!mGetAdServiceListCalled) {
                        buildTvAdServiceListLocked(userId, null);
                        mGetAdServiceListCalled = true;
                    }
                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                    List<TvAdServiceInfo> adServiceList = new ArrayList<>();
                    for (TvAdServiceState state : userState.mAdServiceMap.values()) {
                        adServiceList.add(state.mInfo);
                    }
                    return adServiceList;
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void createSession(final ITvAdClient client, final String serviceId, String type,
                int seq, int userId) {
@@ -767,7 +954,7 @@ public class TvInteractiveAppManagerService extends SystemService {
                        return;
                    }
                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                    TvAdState adState = userState.mAdMap.get(serviceId);
                    TvAdServiceState adState = userState.mAdMap.get(serviceId);
                    if (adState == null) {
                        Slogf.w(TAG, "Failed to find state for serviceId=" + serviceId);
                        sendAdSessionTokenToClientLocked(client, serviceId, null, null, seq);
@@ -885,6 +1072,40 @@ public class TvInteractiveAppManagerService extends SystemService {
        public void startAdService(IBinder sessionToken, int userId) {
        }

        @Override
        public void registerCallback(final ITvAdManagerCallback callback, int userId) {
            int callingPid = Binder.getCallingPid();
            int callingUid = Binder.getCallingUid();
            final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
                    "registerCallback");
            final long identity = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                    if (!userState.mAdCallbacks.register(callback)) {
                        Slog.e(TAG, "client process has already died");
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        @Override
        public void unregisterCallback(ITvAdManagerCallback callback, int userId) {
            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, "unregisterCallback");
            final long identity = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                    userState.mAdCallbacks.unregister(callback);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

    }

    private final class BinderService extends ITvInteractiveAppManager.Stub {
@@ -2637,14 +2858,16 @@ public class TvInteractiveAppManagerService extends SystemService {

    private static final class UserState {
        private final int mUserId;
        // A mapping from the TV AD service ID to its TvAdState.
        private Map<String, TvAdState> mAdMap = new HashMap<>();
        // A mapping from the TV AD service ID to its TvAdServiceState.
        private Map<String, TvAdServiceState> mAdMap = new HashMap<>();
        // A mapping from the name of a TV Interactive App service to its state.
        private final Map<ComponentName, AdServiceState> mAdServiceStateMap = new HashMap<>();
        // A mapping from the token of a TV Interactive App session to its state.
        private final Map<IBinder, AdSessionState> mAdSessionStateMap = new HashMap<>();
        // A mapping from the TV Interactive App ID to its TvInteractiveAppState.
        private Map<String, TvInteractiveAppState> mIAppMap = new HashMap<>();
        // A mapping from the TV AD service ID to its TvAdServiceState.
        private Map<String, TvAdServiceState> mAdServiceMap = new HashMap<>();
        // A mapping from the token of a client to its state.
        private final Map<IBinder, ClientState> mClientStateMap = new HashMap<>();
        // A mapping from the name of a TV Interactive App service to its state.
@@ -2656,6 +2879,8 @@ public class TvInteractiveAppManagerService extends SystemService {
        private final Set<String> mPackageSet = new HashSet<>();
        // A list of all app link infos.
        private final List<AppLinkInfo> mAppLinkInfoList = new ArrayList<>();
        private final RemoteCallbackList<ITvAdManagerCallback> mAdCallbacks =
                new RemoteCallbackList<>();

        // A list of callbacks.
        private final RemoteCallbackList<ITvInteractiveAppManagerCallback> mCallbacks =
@@ -2674,7 +2899,7 @@ public class TvInteractiveAppManagerService extends SystemService {
        private int mIAppNumber;
    }

    private static final class TvAdState {
    private static final class TvAdServiceState {
        private String mAdServiceId;
        private ComponentName mComponentName;
        private TvAdServiceInfo mInfo;