1 /*
2  *      Copyright (C) 2016 Team Kodi
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "MediaDrm.h"
22 #include "MediaDrmOnEventListener.h"
23 #include "UUID.h"
24 #include "HashMap.h"
25 
26 #include "jutils-details.hpp"
27 
28 using namespace jni;
29 
CJNIMediaDrm(const CJNIUUID & uuid)30 CJNIMediaDrm::CJNIMediaDrm(const CJNIUUID& uuid)
31   : CJNIBase("android/media/MediaDrm")
32 {
33   m_object = new_object(GetClassName(), "<init>", "(Ljava/util/UUID;)V",
34                         uuid.get_raw());
35   m_object.setGlobal();
36 }
37 
release() const38 void CJNIMediaDrm::release() const
39 {
40   call_method<void>(m_object,
41     "release", "()V");
42 }
43 
openSession() const44 std::vector<char> CJNIMediaDrm::openSession() const
45 {
46   JNIEnv *env = xbmc_jnienv();
47   jhbyteArray array = call_method<jhbyteArray>(m_object,
48     "openSession", "()[B");
49 
50   std::vector<char> result;
51 
52   if (!env->ExceptionCheck())
53   {
54     jsize size = env->GetArrayLength(array.get());
55     result.resize(size);
56     env->GetByteArrayRegion(array.get(), 0, size, (jbyte*)result.data());
57   }
58 
59   return result;
60 }
61 
closeSession(const std::vector<char> & sessionId) const62 void CJNIMediaDrm::closeSession(const std::vector<char> & sessionId) const
63 {
64   JNIEnv *env = xbmc_jnienv();
65   call_method<void>(m_object,
66     "closeSession", "([B)V", jcast<jhbyteArray, std::vector<char> >(sessionId));
67 }
68 
getPropertyString(const std::string & propertyName) const69 std::string CJNIMediaDrm::getPropertyString(const std::string &propertyName) const
70 {
71   return jcast<std::string>(call_method<jhstring>(m_object,
72     "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
73     jcast<jhstring>(propertyName)));
74 }
75 
getPropertyByteArray(const std::string & propertyName) const76 std::vector<char> CJNIMediaDrm::getPropertyByteArray(const std::string &propertyName) const
77 {
78   JNIEnv *env = xbmc_jnienv();
79   jhbyteArray array = call_method<jhbyteArray>(m_object,
80     "getPropertyByteArray", "(Ljava/lang/String;)[B",
81       jcast<jhstring>(propertyName));
82 
83   std::vector<char> result;
84 
85   if (!env->ExceptionCheck())
86   {
87     jsize size = env->GetArrayLength(array.get());
88     result.resize(size);
89     env->GetByteArrayRegion(array.get(), 0, size, (jbyte*)result.data());
90   }
91   return result;
92 }
93 
setPropertyString(const std::string & propertyName,const std::string & value) const94 void CJNIMediaDrm::setPropertyString(const std::string &propertyName, const std::string &value) const
95 {
96   call_method<void>(m_object,
97     "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
98     jcast<jhstring>(propertyName), jcast<jhstring>(value));
99 }
100 
setPropertyByteArray(const std::string & propertyName,const std::vector<char> & value) const101 void CJNIMediaDrm::setPropertyByteArray(const std::string &propertyName, const std::vector<char> &value) const
102 {
103   JNIEnv *env = xbmc_jnienv();
104   call_method<void>(m_object,
105     "setPropertyByteArray", "(Ljava/lang/String;[B)V",
106     jcast<jhstring>(propertyName), jcast<jhbyteArray, std::vector<char> >(value));
107 }
108 
getKeyRequest(const std::vector<char> & scope,const std::vector<char> & init,const std::string & mimeType,int keyType,const std::map<std::string,std::string> & optionalParameters) const109 CJNIMediaDrmKeyRequest CJNIMediaDrm::getKeyRequest(const std::vector<char> &scope,
110   const std::vector<char> &init, const std::string &mimeType, int keyType,
111   const std::map<std::string, std::string> &optionalParameters) const
112 {
113   JNIEnv *env = xbmc_jnienv();
114 
115   CJNIHashMap hashMap;
116   for (const auto &item : optionalParameters)
117     hashMap.put(jcast<jhstring>(item.first), jcast<jhstring>(item.second));
118 
119   CJNIMediaDrmKeyRequest result =
120     call_method<jhobject>(m_object,
121       "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)Landroid/media/MediaDrm$KeyRequest;",
122       jcast<jhbyteArray, std::vector<char> >(scope), jcast<jhbyteArray, std::vector<char> >(init),
123       jcast<jhstring>(mimeType), keyType, hashMap.get_raw());
124 
125   return result;
126 }
127 
provideKeyResponse(const std::vector<char> & scope,const std::vector<char> & response) const128 std::vector<char> CJNIMediaDrm::provideKeyResponse(const std::vector<char> &scope, const std::vector<char> &response) const
129 {
130   JNIEnv *env = xbmc_jnienv();
131   jhbyteArray array = call_method<jhbyteArray>(m_object,
132     "provideKeyResponse", "([B[B)[B", jcast<jhbyteArray, std::vector<char> >(scope),
133     jcast<jhbyteArray, std::vector<char> >(response));
134 
135   std::vector<char> result;
136 
137   if (!(!array))
138   {
139     jsize size = env->GetArrayLength(array.get());
140     result.resize(size);
141     env->GetByteArrayRegion(array.get(), 0, size, (jbyte*)result.data());
142   }
143   return result;
144 }
145 
getProvisionRequest() const146 CJNIMediaDrmProvisionRequest CJNIMediaDrm::getProvisionRequest() const
147 {
148   return call_method<jhobject>(m_object,
149       "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;");
150 }
151 
provideProvisionResponse(const std::vector<char> & response) const152 void CJNIMediaDrm::provideProvisionResponse(const std::vector<char> &response) const
153 {
154   call_method<void>(m_object,
155     "provideProvisionResponse", "([B)V", jcast<jhbyteArray, std::vector<char> >(response));
156 }
157 
removeKeys(const std::vector<char> & sessionId) const158 void CJNIMediaDrm::removeKeys(const std::vector<char> &sessionId) const
159 {
160   call_method<void>(m_object,
161     "removeKeys", "([B)V", jcast<jhbyteArray, std::vector<char> >(sessionId));
162 }
163 
setOnEventListener(const CJNIMediaDrmOnEventListener & listener) const164 void CJNIMediaDrm::setOnEventListener(const CJNIMediaDrmOnEventListener &listener) const
165 {
166   call_method<void>(m_object, "setOnEventListener",
167     "(Landroid/media/MediaDrm$OnEventListener;)V",
168     listener.get_raw());
169 }
170 
queryKeyStatus(const std::vector<char> & sessionId) const171 std::map<std::string, std::string> CJNIMediaDrm::queryKeyStatus(const std::vector<char> &sessionId) const
172 {
173   if (CJNIBase::GetSDKVersion() >= 23)
174   {
175     std::map<std::string, std::string> result;
176 
177     CJNIHashMap hashMap = call_method<jhobject>(m_object,
178       "queryKeyStatus", "([B)Ljava/util/HashMap;", jcast<jhbyteArray, std::vector<char> >(sessionId));
179     // Get a set with Map.entry from hashmap
180     jhobject entrySet = hashMap.entrySet();
181     // Get the Iterator
182     jhobject iterator =  call_method<jhobject>(entrySet, "iterator", "()Ljava/util/Iterator;");
183     while (call_method<jboolean>(iterator, "hasNext", "()Z"))
184     {
185       jhobject next = call_method<jhobject>(iterator, "next", "()Ljava/util/Map$Entry;");
186       std::string key = jcast<std::string>(call_method<jhstring>(next, "getKey", "()Ljava/lang/Object;"));
187       std::string value = jcast<std::string>(call_method<jhstring>(next, "getValue", "()Ljava/lang/Object;"));
188       result[key] = value;
189     }
190     return result;
191   }
192   return std::map<std::string, std::string>();
193 }
194 
getSecurityLevel(const std::vector<char> & sessionId) const195 int CJNIMediaDrm::getSecurityLevel(const std::vector<char> &sessionId) const
196 {
197   if (CJNIBase::GetSDKVersion() >= 28)
198   {
199     return call_method<int>(m_object,
200       "getSecurityLevel", "([B)I", jcast<jhbyteArray, std::vector<char> >(sessionId));
201   }
202   return -1;
203 }
204 
205 
getMaxSecurityLevel() const206 int CJNIMediaDrm::getMaxSecurityLevel() const
207 {
208   if (CJNIBase::GetSDKVersion() >= 28)
209   {
210     return call_static_method<int>(GetClassName().c_str(),
211       "getMaxSecurityLevel", "()I");
212   }
213   return -1;
214 }
215