1d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/* 2d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Copyright (C) 2017 The Android Open Source Project 3d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 4d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 5d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * you may not use this file except in compliance with the License. 6d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * You may obtain a copy of the License at 7d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 8d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * http://www.apache.org/licenses/LICENSE-2.0 9d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 10d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Unless required by applicable law or agreed to in writing, software 11d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 12d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * See the License for the specific language governing permissions and 14d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * limitations under the License. 15d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 16d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 17d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangpackage android.media; 18d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 19d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.annotation.NonNull; 20d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.annotation.Nullable; 212659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.hardware.cas.V1_0.*; 22dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhangimport android.media.MediaCasException.*; 23d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.Handler; 24d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.HandlerThread; 252659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.os.IHwBinder; 26d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.Looper; 27d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.Message; 28d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.Process; 29d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.RemoteException; 30d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.util.Log; 31d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.util.Singleton; 32d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 332659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport java.util.ArrayList; 342659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang 35d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/** 36d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaCas can be used to obtain keys for descrambling protected media streams, in 37d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * conjunction with {@link android.media.MediaDescrambler}. The MediaCas APIs are 38d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * designed to support conditional access such as those in the ISO/IEC13818-1. 39d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * The CA system is identified by a 16-bit integer CA_system_id. The scrambling 40d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * algorithms are usually proprietary and implemented by vendor-specific CA plugins 41d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * installed on the device. 42d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 43d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * The app is responsible for constructing a MediaCas object for the CA system it 44d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * intends to use. The app can query if a certain CA system is supported using static 45d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * method {@link #isSystemIdSupported}. It can also obtain the entire list of supported 46d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * CA systems using static method {@link #enumeratePlugins}. 47d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 48d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Once the MediaCas object is constructed, the app should properly provision it by 49d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * using method {@link #provision} and/or {@link #processEmm}. The EMMs (Entitlement 50d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * management messages) can be distributed out-of-band, or in-band with the stream. 51d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 52d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * To descramble elementary streams, the app first calls {@link #openSession} to 53addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * generate a {@link Session} object that will uniquely identify a session. A session 54addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * provides a context for subsequent key updates and descrambling activities. The ECMs 55addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * (Entitlement control messages) are sent to the session via method 56addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * {@link Session#processEcm}. 57d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 58d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * The app next constructs a MediaDescrambler object, and initializes it with the 59addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * session using {@link MediaDescrambler#setMediaCasSession}. This ties the 60d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * descrambler to the session, and the descrambler can then be used to descramble 61d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * content secured with the session's key, either during extraction, or during decoding 62d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * with {@link android.media.MediaCodec}. 63d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 64d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * If the app handles sample extraction using its own extractor, it can use 65d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaDescrambler to descramble samples into clear buffers (if the session's license 66d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * doesn't require secure decoders), or descramble a small amount of data to retrieve 67d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * information necessary for the downstream pipeline to process the sample (if the 68d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * session's license requires secure decoders). 69d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 70d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * If the session requires a secure decoder, a MediaDescrambler needs to be provided to 71d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaCodec to descramble samples queued by {@link MediaCodec#queueSecureInputBuffer} 72d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * into protected buffers. The app should use {@link MediaCodec#configure(MediaFormat, 73d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * android.view.Surface, int, MediaDescrambler)} instead of the normal {@link 74d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaCodec#configure(MediaFormat, android.view.Surface, MediaCrypto, int)} method 75d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * to configure MediaCodec. 76d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 77d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <h3>Using Android's MediaExtractor</h3> 78d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 79d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * If the app uses {@link MediaExtractor}, it can delegate the CAS session 80d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * management to MediaExtractor by calling {@link MediaExtractor#setMediaCas}. 81d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaExtractor will take over and call {@link #openSession}, {@link #processEmm} 82addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * and/or {@link Session#processEcm}, etc.. if necessary. 83d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 84d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * When using {@link MediaExtractor}, the app would still need a MediaDescrambler 85d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * to use with {@link MediaCodec} if the licensing requires a secure decoder. The 86addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * session associated with the descrambler of a track can be retrieved by calling 87addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * {@link MediaExtractor#getCasInfo}, and used to initialize a MediaDescrambler 88addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * object for MediaCodec. 89d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p> 90d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <h3>Listeners</h3> 91d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * <p>The app may register a listener to receive events from the CA system using 92d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * method {@link #setEventListener}. The exact format of the event is scheme-specific 93d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and is not specified by this API. 94d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 95addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhangpublic final class MediaCas implements AutoCloseable { 96d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private static final String TAG = "MediaCas"; 97d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private ICas mICas; 98d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private EventListener mListener; 99d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private HandlerThread mHandlerThread; 100d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private EventHandler mEventHandler; 101d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 102d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private static final Singleton<IMediaCasService> gDefault = 103d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang new Singleton<IMediaCasService>() { 104d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 105d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang protected IMediaCasService create() { 1062659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang try { 1072659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return IMediaCasService.getService(); 1082659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } catch (RemoteException e) {} 1092659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return null; 110d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 111d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang }; 112d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 113d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang static IMediaCasService getService() { 114d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return gDefault.get(); 115d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 116d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 117d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private void validateInternalStates() { 118d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mICas == null) { 119d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalStateException(); 120d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 121d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 122d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 123d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private void cleanupAndRethrowIllegalState() { 124d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mICas = null; 125d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalStateException(); 126d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 127d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 128d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private class EventHandler extends Handler 129d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang { 130d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private static final int MSG_CAS_EVENT = 0; 131d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 132d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public EventHandler(Looper looper) { 133d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang super(looper); 134d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 135d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 136d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 137d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public void handleMessage(Message msg) { 138d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (msg.what == MSG_CAS_EVENT) { 1392659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mListener.onEvent(MediaCas.this, msg.arg1, msg.arg2, 1402659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang toBytes((ArrayList<Byte>) msg.obj)); 141d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 142d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 143d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 144d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 145d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private final ICasListener.Stub mBinder = new ICasListener.Stub() { 146d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 1472659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang public void onEvent(int event, int arg, @Nullable ArrayList<Byte> data) 148d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throws RemoteException { 149d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mEventHandler.sendMessage(mEventHandler.obtainMessage( 150d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang EventHandler.MSG_CAS_EVENT, event, arg, data)); 151d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 152d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang }; 153d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 154d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 155d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Describe a CAS plugin with its CA_system_ID and string name. 156d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 157d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Returned as results of {@link #enumeratePlugins}. 158d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 159d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 160d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public static class PluginDescriptor { 161d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private final int mCASystemId; 162d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private final String mName; 163d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 164d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private PluginDescriptor() { 165d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mCASystemId = 0xffff; 166d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mName = null; 167d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 168d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 1692659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang PluginDescriptor(@NonNull HidlCasPluginDescriptor descriptor) { 1702659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mCASystemId = descriptor.caSystemId; 1712659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mName = descriptor.name; 172d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 173d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 174d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public int getSystemId() { 175d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return mCASystemId; 176d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 177d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 178d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @NonNull 179d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public String getName() { 180d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return mName; 181d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 182d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 183d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 184d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public String toString() { 185d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return "PluginDescriptor {" + mCASystemId + ", " + mName + "}"; 186d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 187d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 188d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 1892659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private ArrayList<Byte> toByteArray(@NonNull byte[] data, int offset, int length) { 1902659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang ArrayList<Byte> byteArray = new ArrayList<Byte>(length); 1912659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang for (int i = 0; i < length; i++) { 1922659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang byteArray.add(Byte.valueOf(data[offset + i])); 1932659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 1942659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return byteArray; 1952659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 1962659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang 1972659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private ArrayList<Byte> toByteArray(@Nullable byte[] data) { 1982659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang if (data == null) { 1992659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return new ArrayList<Byte>(); 2002659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 2012659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return toByteArray(data, 0, data.length); 2022659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 2032659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang 2042659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private byte[] toBytes(@NonNull ArrayList<Byte> byteArray) { 2052659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang byte[] data = null; 2062659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang if (byteArray != null) { 2072659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang data = new byte[byteArray.size()]; 2082659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang for (int i = 0; i < data.length; i++) { 2092659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang data[i] = byteArray.get(i); 2102659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 2112659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 2122659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return data; 2132659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 214d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 215addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * Class for an open session with the CA system. 216addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang */ 217addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public final class Session implements AutoCloseable { 2182659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang final ArrayList<Byte> mSessionId; 219addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 2202659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang Session(@NonNull ArrayList<Byte> sessionId) { 221addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang mSessionId = sessionId; 222addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 223addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 224addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang /** 225addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * Set the private data for a session. 226addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 227addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param data byte array of the private data. 228addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 229addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 230addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasException for CAS-specific errors. 231addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 232addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang */ 233addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void setPrivateData(@NonNull byte[] data) 234addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang throws MediaCasException { 235addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang validateInternalStates(); 236addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 237addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang try { 2382659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 2392659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.setSessionPrivateData(mSessionId, toByteArray(data, 0, data.length))); 240addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } catch (RemoteException e) { 241addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang cleanupAndRethrowIllegalState(); 242addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 243addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 244addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 245addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 246addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang /** 247addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * Send a received ECM packet to the specified session of the CA system. 248addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 249addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param data byte array of the ECM data. 250addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param offset position within data where the ECM data begins. 251addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param length length of the data (starting from offset). 252addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 253addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 254addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasException for CAS-specific errors. 255addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 256addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang */ 257addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void processEcm(@NonNull byte[] data, int offset, int length) 258addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang throws MediaCasException { 259addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang validateInternalStates(); 260addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 261addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang try { 2622659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 2632659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.processEcm(mSessionId, toByteArray(data, offset, length))); 264addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } catch (RemoteException e) { 265addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang cleanupAndRethrowIllegalState(); 266addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 267addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 268addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 269addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang /** 270addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * Send a received ECM packet to the specified session of the CA system. 271addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * This is similar to {@link Session#processEcm(byte[], int, int)} 272addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * except that the entire byte array is sent. 273addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 274addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param data byte array of the ECM data. 275addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 276addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 277addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasException for CAS-specific errors. 278addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 279addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang */ 280addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void processEcm(@NonNull byte[] data) throws MediaCasException { 281addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang processEcm(data, 0, data.length); 282addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 283addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 284addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang /** 285addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * Close the session. 286addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * 287addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 288addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 289addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang */ 290addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang @Override 291addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void close() { 292addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang validateInternalStates(); 293addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 294addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang try { 2952659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasStateException.throwExceptionIfNeeded( 2962659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.closeSession(mSessionId)); 297addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } catch (RemoteException e) { 298addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang cleanupAndRethrowIllegalState(); 299addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 300addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 301addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 302addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 3032659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang Session createFromSessionId(@NonNull ArrayList<Byte> sessionId) { 3042659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang if (sessionId == null || sessionId.size() == 0) { 305addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang return null; 306addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 307addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang return new Session(sessionId); 308addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang } 309addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang 310addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang /** 311d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Query if a certain CA system is supported on this device. 312d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 313d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param CA_system_id the id of the CA system. 314d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 315d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @return Whether the specified CA system is supported on this device. 316d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 317d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public static boolean isSystemIdSupported(int CA_system_id) { 318d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang IMediaCasService service = getService(); 319d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 320d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (service != null) { 321d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 322d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return service.isSystemIdSupported(CA_system_id); 323d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 324d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 325d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 326d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return false; 327d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 328d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 329d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 330d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * List all available CA plugins on the device. 331d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 332d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @return an array of descriptors for the available CA plugins. 333d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 334d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public static PluginDescriptor[] enumeratePlugins() { 335d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang IMediaCasService service = getService(); 336d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 337d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (service != null) { 338d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 3392659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang ArrayList<HidlCasPluginDescriptor> descriptors = 3402659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang service.enumeratePlugins(); 3412659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang if (descriptors.size() == 0) { 342d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return null; 343d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 3442659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang PluginDescriptor[] results = new PluginDescriptor[descriptors.size()]; 345d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang for (int i = 0; i < results.length; i++) { 3462659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang results[i] = new PluginDescriptor(descriptors.get(i)); 347d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 348d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return results; 349d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 350d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 351d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 352d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return null; 353d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 354d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 355d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 356d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Instantiate a CA system of the specified system id. 357d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 358d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param CA_system_id The system id of the CA system. 359d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 360d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws UnsupportedCasException if the device does not support the 361d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * specified CA system. 362d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 363d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public MediaCas(int CA_system_id) throws UnsupportedCasException { 364d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 365d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mICas = getService().createPlugin(CA_system_id, mBinder); 366d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch(Exception e) { 367d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang Log.e(TAG, "Failed to create plugin: " + e); 368d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mICas = null; 369d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } finally { 370d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mICas == null) { 371d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new UnsupportedCasException( 372d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Unsupported CA_system_id " + CA_system_id); 373d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 374d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 375d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 376d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 3772659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang IHwBinder getBinder() { 378d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 379d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 380d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return mICas.asBinder(); 381d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 382d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 383d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 384d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * An interface registered by the caller to {@link #setEventListener} 385d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * to receives scheme-specific notifications from a MediaCas instance. 386d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 387d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public interface EventListener { 388d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 389d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Notify the listener of a scheme-specific event from the CA system. 390d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 391d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param MediaCas the MediaCas object to receive this event. 392d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param event an integer whose meaning is scheme-specific. 393d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param arg an integer whose meaning is scheme-specific. 394d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param data a byte array of data whose format and meaning are 395d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * scheme-specific. 396d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 397d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang void onEvent(MediaCas MediaCas, int event, int arg, @Nullable byte[] data); 398d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 399d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 400d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 401d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Set an event listener to receive notifications from the MediaCas instance. 402d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 403d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param listener the event listener to be set. 404d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param handler the handler whose looper the event listener will be called on. 405d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * If handler is null, we'll try to use current thread's looper, or the main 406d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * looper. If neither are available, an internal thread will be created instead. 407d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 408d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public void setEventListener( 409d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Nullable EventListener listener, @Nullable Handler handler) { 410d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mListener = listener; 411d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 412d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mListener == null) { 413d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mEventHandler = null; 414d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return; 415d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 416d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 417d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang Looper looper = (handler != null) ? handler.getLooper() : null; 418d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (looper == null 419d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang && (looper = Looper.myLooper()) == null 420d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang && (looper = Looper.getMainLooper()) == null) { 421d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mHandlerThread == null || !mHandlerThread.isAlive()) { 422d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mHandlerThread = new HandlerThread("MediaCasEventThread", 423d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang Process.THREAD_PRIORITY_FOREGROUND); 424d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mHandlerThread.start(); 425d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 426d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang looper = mHandlerThread.getLooper(); 427d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 428d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mEventHandler = new EventHandler(looper); 429d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 430d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 431d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 432d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Send the private data for the CA system. 433d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 434d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param data byte array of the private data. 435d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 436d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 437dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 438dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 439d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 440dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void setPrivateData(@NonNull byte[] data) throws MediaCasException { 441d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 442d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 443d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 4442659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 4452659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.setPrivateData(toByteArray(data, 0, data.length))); 446d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 447d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 448d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 449d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 450d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 4512659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private class OpenSessionCallback implements ICas.openSessionCallback { 4522659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang public Session mSession; 4532659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang public int mStatus; 4542659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang @Override 4552659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang public void onValues(int status, ArrayList<Byte> sessionId) { 4562659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mStatus = status; 4572659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mSession = createFromSessionId(sessionId); 4582659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 4592659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } 460d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 461625e1804544d830cab803b165f3d415ed369c436Chong Zhang * Open a session to descramble one or more streams scrambled by the 462625e1804544d830cab803b165f3d415ed369c436Chong Zhang * conditional access system. 463d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 464addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @return session the newly opened session. 465d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 466dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 467dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 468dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 469d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 470625e1804544d830cab803b165f3d415ed369c436Chong Zhang public Session openSession() throws MediaCasException { 471d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 472d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 473d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 4742659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang OpenSessionCallback cb = new OpenSessionCallback(); 4752659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.openSession(cb); 4762659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded(cb.mStatus); 4772659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang return cb.mSession; 478d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 479d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 480d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 481d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return null; 482d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 483d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 484d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 485d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Send a received EMM packet to the CA system. 486d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 487d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param data byte array of the EMM data. 488d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param offset position within data where the EMM data begins. 489d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param length length of the data (starting from offset). 490d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 491d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 492dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 493dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 494d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 495dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void processEmm(@NonNull byte[] data, int offset, int length) 496dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang throws MediaCasException { 497d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 498d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 499d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 5002659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 5012659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.processEmm(toByteArray(data, offset, length))); 502d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 503d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 504d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 505d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 506d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 507d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 508d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Send a received EMM packet to the CA system. This is similar to 509d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * {@link #processEmm(byte[], int, int)} except that the entire byte 510d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * array is sent. 511d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 512d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param data byte array of the EMM data. 513d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 514d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 515dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 516dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 517d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 518dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void processEmm(@NonNull byte[] data) throws MediaCasException { 519d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang processEmm(data, 0, data.length); 520d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 521d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 522d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 523d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Send an event to a CA system. The format of the event is scheme-specific 524d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and is opaque to the framework. 525d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 526d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param event an integer denoting a scheme-specific event to be sent. 527d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param arg a scheme-specific integer argument for the event. 528d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param data a byte array containing scheme-specific data for the event. 529d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 530d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 531dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 532dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 533d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 534dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void sendEvent(int event, int arg, @Nullable byte[] data) 535dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang throws MediaCasException { 536d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 537d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 538d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 5392659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 5402659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.sendEvent(event, arg, toByteArray(data))); 541d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 542d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 543d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 544d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 545d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 546d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 547d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Initiate a provisioning operation for a CA system. 548d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 549d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param provisionString string containing information needed for the 550d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * provisioning operation, the format of which is scheme and implementation 551d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * specific. 552d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 553d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 554dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 555dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 556d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 557dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void provision(@NonNull String provisionString) throws MediaCasException { 558d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 559d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 560d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 5612659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 5622659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.provision(provisionString)); 563d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 564d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 565d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 566d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 567d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 568d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 569d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Notify the CA system to refresh entitlement keys. 570d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 571d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param refreshType the type of the refreshment. 572d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param refreshData private data associated with the refreshment. 573d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 574d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the MediaCas instance is not valid. 575dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasException for CAS-specific errors. 576dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 577d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 578dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang public void refreshEntitlements(int refreshType, @Nullable byte[] refreshData) 579dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang throws MediaCasException { 580d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 581d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 582d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 5832659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasException.throwExceptionIfNeeded( 5842659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mICas.refreshEntitlements(refreshType, toByteArray(refreshData))); 585d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 586d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 587d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 588d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 589d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 590addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang @Override 591addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void close() { 592d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mICas != null) { 593d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 594d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mICas.release(); 595d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 596d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } finally { 597d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mICas = null; 598d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 599d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 600d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 601d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 602d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 603d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang protected void finalize() { 604addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang close(); 605d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 606d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang}