1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.tv.tuner; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.media.tv.tuner.Tuner.Result; 24 import android.media.tv.tuner.filter.Filter; 25 import android.util.Log; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.util.Objects; 30 31 /** 32 * This class is used to interact with descramblers. 33 * 34 * <p> Descrambler is a hardware component used to descramble data. 35 * 36 * <p> This class controls the TIS interaction with Tuner HAL. 37 * 38 * @hide 39 */ 40 @SystemApi 41 public class Descrambler implements AutoCloseable { 42 /** @hide */ 43 @IntDef(prefix = "PID_TYPE_", value = {PID_TYPE_T, PID_TYPE_MMTP}) 44 @Retention(RetentionPolicy.SOURCE) 45 public @interface PidType {} 46 47 /** 48 * Packet ID is used to specify packets in transport stream. 49 */ 50 public static final int PID_TYPE_T = 1; 51 /** 52 * Packet ID is used to specify packets in MMTP. 53 */ 54 public static final int PID_TYPE_MMTP = 2; 55 56 private static final String TAG = "Descrambler"; 57 58 59 private long mNativeContext; 60 private boolean mIsClosed = false; 61 private final Object mLock = new Object(); 62 nativeAddPid(int pidType, int pid, Filter filter)63 private native int nativeAddPid(int pidType, int pid, Filter filter); nativeRemovePid(int pidType, int pid, Filter filter)64 private native int nativeRemovePid(int pidType, int pid, Filter filter); nativeSetKeyToken(byte[] keyToken)65 private native int nativeSetKeyToken(byte[] keyToken); nativeClose()66 private native int nativeClose(); 67 68 // Called by JNI code Descrambler()69 private Descrambler() {} 70 71 /** 72 * Add packets' PID to the descrambler for descrambling. 73 * 74 * The descrambler will start descrambling packets with this PID. Multiple PIDs can be added 75 * into one descrambler instance because descambling can happen simultaneously on packets 76 * from different PIDs. 77 * 78 * If the Descrambler previously contained a filter for the PID, the old filter is replaced 79 * by the specified filter. 80 * 81 * @param pidType the type of the PID. 82 * @param pid the PID of packets to start to be descrambled. 83 * @param filter an optional filter instance to identify upper stream. 84 * @return result status of the operation. 85 */ 86 @Result addPid(@idType int pidType, int pid, @Nullable Filter filter)87 public int addPid(@PidType int pidType, int pid, @Nullable Filter filter) { 88 synchronized (mLock) { 89 TunerUtils.checkResourceState(TAG, mIsClosed); 90 return nativeAddPid(pidType, pid, filter); 91 } 92 } 93 94 /** 95 * Remove packets' PID from the descrambler 96 * 97 * The descrambler will stop descrambling packets with this PID. 98 * 99 * @param pidType the type of the PID. 100 * @param pid the PID of packets to stop to be descrambled. 101 * @param filter an optional filter instance to identify upper stream. 102 * @return result status of the operation. 103 */ 104 @Result removePid(@idType int pidType, int pid, @Nullable Filter filter)105 public int removePid(@PidType int pidType, int pid, @Nullable Filter filter) { 106 synchronized (mLock) { 107 TunerUtils.checkResourceState(TAG, mIsClosed); 108 return nativeRemovePid(pidType, pid, filter); 109 } 110 } 111 112 /** 113 * Set a key token to link descrambler to a key slot. Use {@link isValidKeyToken(byte[])} to 114 * validate the key token format. Invalid key token would cause no-op and return 115 * {@link Tuner.RESULT_INVALID_ARGUMENT}. 116 * 117 * <p>A descrambler instance can have only one key slot to link, but a key slot can hold a few 118 * keys for different purposes. {@link Tuner.VOID_KEYTOKEN} is considered valid. 119 * 120 * @param keyToken the token to be used to link the key slot. Use {@link Tuner#VOID_KEYTOKEN} 121 * to remove the current key from descrambler. If the current keyToken comes from a 122 * MediaCas session, use {@link Tuner#VOID_KEYTOKEN} to remove current key before 123 * closing the MediaCas session. 124 * @return result status of the operation. 125 */ 126 @Result setKeyToken(@onNull byte[] keyToken)127 public int setKeyToken(@NonNull byte[] keyToken) { 128 synchronized (mLock) { 129 TunerUtils.checkResourceState(TAG, mIsClosed); 130 Objects.requireNonNull(keyToken, "key token must not be null"); 131 if (!isValidKeyToken(keyToken)) { 132 return Tuner.RESULT_INVALID_ARGUMENT; 133 } 134 return nativeSetKeyToken(keyToken); 135 } 136 } 137 138 /** 139 * Validate the key token format as the parameter of {@link setKeyToken(byte[])}. 140 * 141 * <p>The key token is expected to be less than 128 bits. 142 * 143 * @param keyToken the token to be validated. 144 * @return true if the given key token is a valid one. 145 */ isValidKeyToken(@onNull byte[] keyToken)146 public static boolean isValidKeyToken(@NonNull byte[] keyToken) { 147 if (keyToken.length == 0 || keyToken.length > 16) { 148 Log.d(TAG, "Invalid key token size: " + (keyToken.length * 8) + " bit."); 149 return false; 150 } 151 return true; 152 } 153 154 /** 155 * Release the descrambler instance. 156 */ 157 @Override close()158 public void close() { 159 synchronized (mLock) { 160 if (mIsClosed) { 161 return; 162 } 163 int res = nativeClose(); 164 if (res != Tuner.RESULT_SUCCESS) { 165 TunerUtils.throwExceptionForResult(res, "Failed to close descrambler"); 166 } else { 167 mIsClosed = true; 168 } 169 } 170 } 171 } 172