1a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang/* 2a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * Copyright (C) 2017 The Android Open Source Project 3a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * 4a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 5a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * you may not use this file except in compliance with the License. 6a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * You may obtain a copy of the License at 7a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * 8a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * http://www.apache.org/licenses/LICENSE-2.0 9a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * 10a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * Unless required by applicable law or agreed to in writing, software 11a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 12a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * See the License for the specific language governing permissions and 14a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang * limitations under the License. 15a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang */ 16a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 17a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#ifndef ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ 18a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ 19a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 20a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include <dirent.h> 21a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include <dlfcn.h> 22a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include "SharedLibrary.h" 23a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include <utils/KeyedVector.h> 24a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include <utils/Mutex.h> 25a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#include <media/cas/CasAPI.h> 26a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 27a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangusing namespace std; 28a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 29a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangnamespace android { 30a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangnamespace hardware { 31a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangnamespace cas { 32a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangnamespace V1_0 { 33a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangnamespace implementation { 34a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 35a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 36a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangclass FactoryLoader { 37a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangpublic: 38a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang FactoryLoader(const char *name) : 39a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mFactory(NULL), mCreateFactoryFuncName(name) {} 40a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 41a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang virtual ~FactoryLoader() { closeFactory(); } 42a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 43a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang bool findFactoryForScheme( 44a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang int32_t CA_system_id, 45a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang sp<SharedLibrary> *library = NULL, 46a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang T** factory = NULL); 47a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 48a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results); 49a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 50a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangprivate: 51a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang typedef T*(*CreateFactoryFunc)(); 52a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 53a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang Mutex mMapLock; 54a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang T* mFactory; 55a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang const char *mCreateFactoryFuncName; 56a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang sp<SharedLibrary> mLibrary; 57a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap; 58a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap; 59a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 60a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang bool loadFactoryForSchemeFromPath( 61a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang const String8 &path, 62a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang int32_t CA_system_id, 63a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang sp<SharedLibrary> *library, 64a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang T** factory); 65a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 66a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang bool queryPluginsFromPath( 67a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang const String8 &path, 68a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang vector<HidlCasPluginDescriptor>* results); 69a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 70a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang bool openFactory(const String8 &path); 71a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang void closeFactory(); 72a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang}; 73a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 74a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 75a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangbool FactoryLoader<T>::findFactoryForScheme( 76a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) { 77a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (library != NULL) { 78a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang library->clear(); 79a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 80a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (factory != NULL) { 81a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang *factory = NULL; 82a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 83a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 84a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang Mutex::Autolock autoLock(mMapLock); 85a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 86a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang // first check cache 87a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id); 88a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (index >= 0) { 89a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return loadFactoryForSchemeFromPath( 90a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mCASystemIdToLibraryPathMap[index], 91a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang CA_system_id, library, factory); 92a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 93a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 94a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang // no luck, have to search 95a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang String8 dirPath("/vendor/lib/mediacas"); 96a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang DIR* pDir = opendir(dirPath.string()); 97a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 98a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (pDir == NULL) { 99a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ALOGE("Failed to open plugin directory %s", dirPath.string()); 100a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 101a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 102a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 103a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang struct dirent* pEntry; 104a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang while ((pEntry = readdir(pDir))) { 105a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang String8 pluginPath = dirPath + "/" + pEntry->d_name; 106a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (pluginPath.getPathExtension() == ".so") { 107a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (loadFactoryForSchemeFromPath( 108a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang pluginPath, CA_system_id, library, factory)) { 109a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath); 110a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closedir(pDir); 111a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 112a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return true; 113a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 114a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 115a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 116a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 117a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closedir(pDir); 118a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 119a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ALOGE("Failed to find plugin"); 120a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 121a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 122a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 123a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 124a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangbool FactoryLoader<T>::enumeratePlugins( 125a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang vector<HidlCasPluginDescriptor>* results) { 126a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ALOGI("enumeratePlugins"); 127a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 128a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang results->clear(); 129a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 130a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang String8 dirPath("/vendor/lib/mediacas"); 131a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang DIR* pDir = opendir(dirPath.string()); 132a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 133a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (pDir == NULL) { 134a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ALOGE("Failed to open plugin directory %s", dirPath.string()); 135a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 136a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 137a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 138a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang Mutex::Autolock autoLock(mMapLock); 139a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 140a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang struct dirent* pEntry; 141a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang while ((pEntry = readdir(pDir))) { 142a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang String8 pluginPath = dirPath + "/" + pEntry->d_name; 143a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (pluginPath.getPathExtension() == ".so") { 144a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang queryPluginsFromPath(pluginPath, results); 145a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 146a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 147a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return true; 148a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 149a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 150a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 151a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangbool FactoryLoader<T>::loadFactoryForSchemeFromPath( 152a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang const String8 &path, int32_t CA_system_id, 153a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang sp<SharedLibrary> *library, T** factory) { 154a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closeFactory(); 155a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 156a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) { 157a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closeFactory(); 158a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 159a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 160a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 161a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (library != NULL) { 162a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang *library = mLibrary; 163a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 164a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (factory != NULL) { 165a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang *factory = mFactory; 166a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 167a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return true; 168a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 169a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 170a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 171a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangbool FactoryLoader<T>::queryPluginsFromPath( 172a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang const String8 &path, vector<HidlCasPluginDescriptor>* results) { 173a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closeFactory(); 174a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 175a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang vector<CasPluginDescriptor> descriptors; 176a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) { 177a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang closeFactory(); 178a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 179a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 180a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 181a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang for (auto it = descriptors.begin(); it != descriptors.end(); it++) { 182a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang results->push_back( HidlCasPluginDescriptor { 183a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang .caSystemId = it->CA_system_id, 184a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang .name = it->name.c_str()}); 185a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 186a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return true; 187a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 188a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 189a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 190a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangbool FactoryLoader<T>::openFactory(const String8 &path) { 191a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang // get strong pointer to open shared library 192a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 193a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (index >= 0) { 194a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 195a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } else { 196a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang index = mLibraryPathToOpenLibraryMap.add(path, NULL); 197a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 198a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 199a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (!mLibrary.get()) { 200a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mLibrary = new SharedLibrary(path); 201a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (!*mLibrary) { 202a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 203a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 204a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 205a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); 206a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 207a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 208a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang CreateFactoryFunc createFactory = 209a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName); 210a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang if (createFactory == NULL || (mFactory = createFactory()) == NULL) { 211a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return false; 212a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang } 213a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang return true; 214a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 215a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 216a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangtemplate <class T> 217a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhangvoid FactoryLoader<T>::closeFactory() { 218a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang delete mFactory; 219a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mFactory = NULL; 220a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang mLibrary.clear(); 221a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} 222a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 223a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} // namespace implementation 224a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} // namespace V1_0 225a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} // namespace cas 226a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} // namespace hardware 227a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang} // namespace android 228a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang 229a4f6751e49cca8cd1b673a3917c38ae0620754fcChong Zhang#endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_ 230