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