diff options
| author | 2022-03-18 07:39:08 +0000 | |
|---|---|---|
| committer | 2022-03-18 07:39:08 +0000 | |
| commit | 063200b58e77a005e5a5637c1e1df71ff5fc751c (patch) | |
| tree | 5888ccb16eee9100cfe1ba3075611b16b5119c4d | |
| parent | b96b2c755fdae6967f4d070741304477403005e3 (diff) | |
| parent | 553d6fb7c50158f606e39eb1687628c712d1d37e (diff) | |
Merge "TIAF: add signing request and result" into tm-dev
9 files changed, 255 insertions, 2 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 3f12b6ca7d64..064d998219c2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -26135,6 +26135,7 @@ package android.media.tv.interactive { field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type"; field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri"; field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri"; + field public static final String INTENT_KEY_COMMAND_TYPE = "command_type"; field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id"; field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id"; field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3 @@ -26209,6 +26210,7 @@ package android.media.tv.interactive { method public abstract boolean onSetSurface(@Nullable android.view.Surface); method public void onSetTeletextAppEnabled(boolean); method public void onSignalStrength(int); + method public void onSigningResult(@NonNull String, @NonNull byte[]); method public void onStartInteractiveApp(); method public void onStopInteractiveApp(); method public void onStreamVolume(float); @@ -26227,6 +26229,7 @@ package android.media.tv.interactive { method @CallSuper public void requestCurrentChannelLcn(); method @CallSuper public void requestCurrentChannelUri(); method @CallSuper public void requestCurrentTvInputId(); + method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]); method @CallSuper public void requestStreamVolume(); method @CallSuper public void requestTrackInfoList(); method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle); @@ -26268,6 +26271,7 @@ package android.media.tv.interactive { method public void sendCurrentChannelLcn(int); method public void sendCurrentChannelUri(@Nullable android.net.Uri); method public void sendCurrentTvInputId(@Nullable String); + method public void sendSigningResult(@NonNull String, @NonNull byte[]); method public void sendStreamVolume(float); method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>); method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback); @@ -26276,6 +26280,9 @@ package android.media.tv.interactive { method public int setTvView(@Nullable android.media.tv.TvView); method public void startInteractiveApp(); method public void stopInteractiveApp(); + field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias"; + field public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate"; + field public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key"; } public static interface TvInteractiveAppView.OnUnhandledInputEventListener { @@ -26289,6 +26296,7 @@ package android.media.tv.interactive { method public void onRequestCurrentChannelLcn(@NonNull String); method public void onRequestCurrentChannelUri(@NonNull String); method public void onRequestCurrentTvInputId(@NonNull String); + method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]); method public void onRequestStreamVolume(@NonNull String); method public void onRequestTrackInfoList(@NonNull String); method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl index a3e58d16f655..c8c6f66aa0ed 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl @@ -44,5 +44,7 @@ oneway interface ITvInteractiveAppClient { void onRequestStreamVolume(int seq); void onRequestTrackInfoList(int seq); void onRequestCurrentTvInputId(int seq); + void onRequestSigning( + in String id, in String algorithm, in String alias, in byte[] data, int seq); void onAdRequest(in AdRequest request, int Seq); } diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl index 839118265732..eb012721445c 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl @@ -50,6 +50,8 @@ interface ITvInteractiveAppManager { void sendStreamVolume(in IBinder sessionToken, float volume, int userId); void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId); void sendCurrentTvInputId(in IBinder sessionToken, in String inputId, int userId); + void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result, + int userId); void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type, int seq, int userId); void releaseSession(in IBinder sessionToken, int userId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl index c449d2475428..c784b09e87fc 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl @@ -42,6 +42,7 @@ oneway interface ITvInteractiveAppSession { void sendStreamVolume(float volume); void sendTrackInfoList(in List<TvTrackInfo> tracks); void sendCurrentTvInputId(in String inputId); + void sendSigningResult(in String signingId, in byte[] result); void release(); void notifyTuned(in Uri channelUri); void notifyTrackSelected(int type, in String trackId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl index 385f0d4f766a..f74b2bac957b 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl @@ -43,5 +43,6 @@ oneway interface ITvInteractiveAppSessionCallback { void onRequestStreamVolume(); void onRequestTrackInfoList(); void onRequestCurrentTvInputId(); + void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data); void onAdRequest(in AdRequest request); } diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index 83ff0f50f1a3..90f32593ed78 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -249,7 +249,7 @@ public final class TvInteractiveAppManager { * * @see #sendAppLinkCommand(String, Bundle) * @see #ACTION_APP_LINK_COMMAND - * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getId() + * @see TvInteractiveAppServiceInfo#getId() */ public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id"; @@ -285,6 +285,16 @@ public final class TvInteractiveAppManager { */ public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri"; + /** + * Intent key for command type. It's used to send app command to TV app. The value of this key + * could vary according to TV apps. + * <p>Type: String + * + * @see #sendAppLinkCommand(String, Bundle) + * @see #ACTION_APP_LINK_COMMAND + */ + public static final String INTENT_KEY_COMMAND_TYPE = "command_type"; + private final ITvInteractiveAppManager mService; private final int mUserId; @@ -478,6 +488,19 @@ public final class TvInteractiveAppManager { } @Override + public void onRequestSigning( + String id, String algorithm, String alias, byte[] data, int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postRequestSigning(id, algorithm, alias, data); + } + } + + @Override public void onSessionStateChanged(int state, int err, int seq) { synchronized (mSessionCallbackRecordMap) { SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); @@ -1024,6 +1047,18 @@ public final class TvInteractiveAppManager { } } + void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.sendSigningResult(mToken, signingId, result, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Sets the {@link android.view.Surface} for this session. * @@ -1657,6 +1692,15 @@ public final class TvInteractiveAppManager { }); } + void postRequestSigning(String id, String algorithm, String alias, byte[] data) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onRequestSigning(mSession, id, algorithm, alias, data); + } + }); + } + void postAdRequest(final AdRequest request) { mHandler.post(new Runnable() { @Override @@ -1794,12 +1838,27 @@ public final class TvInteractiveAppManager { * called. * * @param session A {@link TvInteractiveAppService.Session} associated with this callback. - * @hide */ public void onRequestCurrentTvInputId(Session session) { } /** + * This is called when + * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is + * called. + * + * @param session A {@link TvInteractiveAppService.Session} associated with this callback. + * @param signingId the ID to identify the request. + * @param algorithm the standard name of the signature algorithm requested, such as + * MD5withRSA, SHA256withDSA, etc. + * @param alias the alias of the corresponding {@link java.security.KeyStore}. + * @param data the original bytes to be signed. + */ + public void onRequestSigning( + Session session, String signingId, String algorithm, String alias, byte[] data) { + } + + /** * This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is * called. * diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java index 316fbbab6d37..100c6d3947bb 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java @@ -452,6 +452,17 @@ public abstract class TvInteractiveAppService extends Service { } /** + * Receives signing result. + * @param signingId the ID to identify the request. It's the same as the corresponding ID in + * {@link Session#requestSigning(String, String, String, byte[])} + * @param result the signed result. + * + * @see #requestSigning(String, String, String, byte[]) + */ + public void onSigningResult(@NonNull String signingId, @NonNull byte[] result) { + } + + /** * Called when the application sets the surface. * * <p>The TV Interactive App service should render interactive app UI onto the given @@ -877,6 +888,47 @@ public abstract class TvInteractiveAppService extends Service { } /** + * Requests signing of the given data. + * + * <p>This is used when the corresponding server of the broadcast-independent interactive + * app requires signing during handshaking, and the interactive app service doesn't have + * the built-in private key. The private key is provided by the content providers and + * pre-built in the related app, such as TV app. + * + * @param signingId the ID to identify the request. When a result is received, this ID can + * be used to correlate the result with the request. + * @param algorithm the standard name of the signature algorithm requested, such as + * MD5withRSA, SHA256withDSA, etc. The name is from standards like + * FIPS PUB 186-4 and PKCS #1. + * @param alias the alias of the corresponding {@link java.security.KeyStore}. + * @param data the original bytes to be signed. + * + * @see #onSigningResult(String, byte[]) + * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle) + * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS + */ + @CallSuper + public void requestSigning(@NonNull String signingId, @NonNull String algorithm, + @NonNull String alias, @NonNull byte[] data) { + executeOrPostRunnableOnMainThread(new Runnable() { + @MainThread + @Override + public void run() { + try { + if (DEBUG) { + Log.d(TAG, "requestSigning"); + } + if (mSessionCallback != null) { + mSessionCallback.onRequestSigning(signingId, algorithm, alias, data); + } + } catch (RemoteException e) { + Log.w(TAG, "error in requestSigning", e); + } + } + }); + } + + /** * Sends an advertisement request to be processed by the related TV input. * * @param request The advertisement request @@ -945,6 +997,10 @@ public abstract class TvInteractiveAppService extends Service { onCurrentTvInputId(inputId); } + void sendSigningResult(String signingId, byte[] result) { + onSigningResult(signingId, result); + } + void release() { onRelease(); if (mSurface != null) { @@ -1413,6 +1469,11 @@ public abstract class TvInteractiveAppService extends Service { } @Override + public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) { + mSessionImpl.sendSigningResult(signingId, result); + } + + @Override public void release() { mSessionImpl.scheduleMediaViewCleanup(); mSessionImpl.release(); diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java index 212051120e77..8fc5d807c7df 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java @@ -46,6 +46,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewRootImpl; +import java.security.KeyStore; import java.util.List; import java.util.concurrent.Executor; @@ -61,6 +62,28 @@ public class TvInteractiveAppView extends ViewGroup { private static final int UNSET_TVVIEW_SUCCESS = 3; private static final int UNSET_TVVIEW_FAIL = 4; + /** + * Used to share client {@link java.security.cert.Certificate} with + * {@link TvInteractiveAppService}. + * @see #createBiInteractiveApp(Uri, Bundle) + * @see java.security.cert.Certificate + */ + public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate"; + /** + * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}. + * @see #createBiInteractiveApp(Uri, Bundle) + * @see KeyStore#aliases() + */ + public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias"; + /** + * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}. + * <p>The private key is optional. It is used to encrypt data when necessary. + * + * @see #createBiInteractiveApp(Uri, Bundle) + * @see java.security.PrivateKey + */ + public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key"; + private final TvInteractiveAppManager mTvInteractiveAppManager; private final Handler mHandler = new Handler(); private final Object mCallbackLock = new Object(); @@ -513,6 +536,27 @@ public class TvInteractiveAppView extends ViewGroup { } } + /** + * Sends signing result to related TV interactive app. + * + * <p>This is used when the corresponding server of the broadcast-independent interactive + * app requires signing during handshaking, and the interactive app service doesn't have + * the built-in private key. The private key is provided by the content providers and + * pre-built in the related app, such as TV app. + * + * @param signingId the ID to identify the request. It's the same as the corresponding ID in + * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} + * @param result the signed result. + */ + public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) { + if (DEBUG) { + Log.d(TAG, "sendSigningResult"); + } + if (mSession != null) { + mSession.sendSigningResult(signingId, result); + } + } + private void resetInternal() { mSessionCallback = null; if (mSession != null) { @@ -725,6 +769,22 @@ public class TvInteractiveAppView extends ViewGroup { public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) { } + /** + * This is called when + * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is + * called. + * + * @param iAppServiceId The ID of the TV interactive app service bound to this view. + * @param signingId the ID to identify the request. + * @param algorithm the standard name of the signature algorithm requested, such as + * MD5withRSA, SHA256withDSA, etc. + * @param alias the alias of the corresponding {@link java.security.KeyStore}. + * @param data the original bytes to be signed. + */ + public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId, + @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) { + } + } /** @@ -1031,5 +1091,20 @@ public class TvInteractiveAppView extends ViewGroup { mCallback.onRequestCurrentTvInputId(mIAppServiceId); } } + + @Override + public void onRequestSigning( + Session session, String id, String algorithm, String alias, byte[] data) { + if (DEBUG) { + Log.d(TAG, "onRequestSigning"); + } + if (this != mSessionCallback) { + Log.w(TAG, "onRequestSigning - session not created"); + return; + } + if (mCallback != null) { + mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data); + } + } } } diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java index 6adf733ddae9..c252043028c9 100644 --- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java +++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java @@ -1360,6 +1360,32 @@ public class TvInteractiveAppManagerService extends SystemService { } @Override + public void sendSigningResult( + IBinder sessionToken, String signingId, byte[] result, int userId) { + if (DEBUG) { + Slogf.d(TAG, "sendSigningResult(signingId=%s)", signingId); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "sendSigningResult"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = getSessionStateLocked(sessionToken, callingUid, + resolvedUserId); + getSessionLocked(sessionState).sendSigningResult(signingId, result); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in sendSigningResult", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void setSurface(IBinder sessionToken, Surface surface, int userId) { final int callingUid = Binder.getCallingUid(); final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, @@ -2221,6 +2247,24 @@ public class TvInteractiveAppManagerService extends SystemService { } @Override + public void onRequestSigning(String id, String algorithm, String alias, byte[] data) { + synchronized (mLock) { + if (DEBUG) { + Slogf.d(TAG, "onRequestSigning"); + } + if (mSessionState.mSession == null || mSessionState.mClient == null) { + return; + } + try { + mSessionState.mClient.onRequestSigning( + id, algorithm, alias, data, mSessionState.mSeq); + } catch (RemoteException e) { + Slogf.e(TAG, "error in onRequestSigning", e); + } + } + } + + @Override public void onAdRequest(AdRequest request) { synchronized (mLock) { if (DEBUG) { |