void TextureTracker::update(int textureId, bool ghost, String8 name) { Mutex::Autolock _l(mLock); TextureEntry entry(textureId); ssize_t index = mMemoryList.indexOf(entry); if (index >= 0) { TextureEntry& item = mMemoryList.editItemAt(index); TTLOGD("[TT]update before %s %d %d %d %d %d\n", item.mName.string(), item.mId, item.mWidth, item.mHeight, item.mMemory, item.mGhost); item.mGhost = ghost; if (name.isEmpty()) { if (!ghost) { item.mName = mViews.top(); } } else { item.mName = name; } entry = mMemoryList.itemAt(index); TTLOGD("[TT]update after %s %d %d %d %d %d\n", entry.mName.string(), entry.mId, entry.mWidth, entry.mHeight, entry.mMemory, entry.mGhost); } else { TTLOGD("[TT]update not found %d", textureId); } }
bool ParamsManager:: splitInt(String8 const& s8Input, Vector<int>& rOutput) { rOutput.clear(); // if ( s8Input.isEmpty() ) { MY_LOGW("empty string"); return false; } // char const*start = s8Input.string(); char *end = NULL; do { int value = ::strtol(start, &end, 10); if ( start == end ) { MY_LOGW_IF(0, "no digits in str:%s", s8Input.string()); return false; } rOutput.push_back(value); MY_LOGD_IF(0, "%d", value); start = end + 1; } while ( end && *end ); // return (rOutput.size() > 0); }
/****************************************************************************** * Splits a comma delimited string to a List of int Vector. * Example string: "(10000,26623),(10000,30000)" *******************************************************************************/ bool ParamsManager:: splitRange(String8 const& s8Input, List< Vector<int> >& rOutput) { rOutput.clear(); // if ( s8Input.isEmpty() ) { MY_LOGW("empty string"); return false; } // int endIndex, fromIndex = 1; int endIndex_input = s8Input.length()-1; if ( s8Input[0] != '(' || s8Input[endIndex_input] != ')' ) { MY_LOGW("Invalid range list string=%s", s8Input.string()); return false; } // do { endIndex = s8Input.find("),(", fromIndex); if (endIndex == -1) endIndex = endIndex_input; // Vector<int> vOut; String8 const s8SubString(s8Input.string()+fromIndex, endIndex-fromIndex); if ( splitInt(s8SubString, vOut) ) { rOutput.push_back(vOut); } // fromIndex = endIndex + 3; } while (endIndex != endIndex_input); // return (rOutput.size() > 0); }
// static sp<DataSource> DataSource::CreateFromURI( const char *uri, const KeyedVector<String8, String8> *headers) { bool isWidevine = !strncasecmp("widevine://", uri, 11); sp<DataSource> source; if (!strncasecmp("file://", uri, 7)) { source = new FileSource(uri + 7); } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8) || isWidevine) { sp<HTTPBase> httpSource = HTTPBase::Create(); String8 tmp; if (isWidevine) { tmp = String8("http://"); tmp.append(uri + 11); uri = tmp.string(); } if (httpSource->connect(uri, headers) != OK) { return NULL; } if (!isWidevine) { String8 cacheConfig; bool disconnectAtHighwatermark; if (headers != NULL) { KeyedVector<String8, String8> copy = *headers; NuCachedSource2::RemoveCacheSpecificHeaders( ©, &cacheConfig, &disconnectAtHighwatermark); } source = new NuCachedSource2( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string()); } else { // We do not want that prefetching, caching, datasource wrapper // in the widevine:// case. source = httpSource; } # if CHROMIUM_AVAILABLE } else if (!strncasecmp("data:", uri, 5)) { source = createDataUriSource(uri); #endif } else { // Assume it's a filename. source = new FileSource(uri); } if (source == NULL || source->initCheck() != OK) { return NULL; } return source; }
status_t PropertyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); if (keyToken.isEmpty()) { ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->nextChar() != '=') { ALOGE("%s: Expected '=' between property key and value.", mTokenizer->getLocation().string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 valueToken = mTokenizer->nextToken(WHITESPACE); if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { ALOGE("%s: Found reserved character '\\' or '\"' in property value.", mTokenizer->getLocation().string()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(), mTokenizer->peekRemainderOfLine().string()); return BAD_VALUE; } if (mMap->hasProperty(keyToken)) { ALOGE("%s: Duplicate property value for key '%s'.", mTokenizer->getLocation().string(), keyToken.string()); return BAD_VALUE; } mMap->addProperty(keyToken, valueToken); } mTokenizer->nextLine(); } return NO_ERROR; }
static int readFromFile(const String8& path, char* buf, size_t size) { if (path.isEmpty()) return -1; int fd = open(path.string(), O_RDONLY, 0); if (fd == -1) { ALOGE("Could not open '%s'", path.string()); return -1; } ssize_t count = read(fd, buf, size); if (count > 0) { while (count > 0 && buf[count-1] == '\n') count--; buf[count] = '\0'; } else { buf[0] = '\0'; } close(fd); return count; }
int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) { char *cp = NULL; if (path.isEmpty()) return -1; int fd = open(path.string(), O_RDONLY, 0); if (fd == -1) { KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string()); return -1; } ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size)); if (count > 0) cp = (char *)memrchr(buf, '\n', count); if (cp) *cp = '\0'; else buf[0] = '\0'; close(fd); return count; }
void DisplayDevice::setDisplayName(const String8& displayName) { if (!displayName.isEmpty()) { // never override the name with an empty name mDisplayName = displayName; } }
status_t CamAdapter:: setParameters() { MY_LOGD("+"); status_t ret = OK; // //(1) must set to mpPreviewCmdQueThread earlier than to 3A if ( mpPreviewCmdQueThread != 0 ) { if ( ! mpPreviewCmdQueThread->setParameters() ) { MY_LOGE("mpPreviewCmdQueThread->setParameters fail"); } } else { MY_LOGE("mpPreviewCmdQueThread is NULL"); } // (2) get Param from 3A NS3A::Param_T cam3aParam; Hal3ABase* p3AHal = Hal3ABase::createInstance(DevMetaInfo::queryHalSensorDev(getOpenId())); if ( ! p3AHal ) { MY_LOGE("p3AHal == NULL"); return INVALID_OPERATION; } // if ( ! p3AHal->getParams(cam3aParam) ) { MY_LOGE("getParams fail"); ret = INVALID_OPERATION; goto lbExit; } //(3) set Param to 3A #define UPDATE_PARAMS(param, eMapXXX, key) \ do { \ String8 const s = mpParamsMgr->getStr(key); \ if ( ! s.isEmpty() ) { \ param = PARAMSMANAGER_MAP_INST(eMapXXX)->valueFor(s); \ } \ } while (0) // DEFAULT DEFINITION CATEGORY cam3aParam.i4MinFps = 5000; cam3aParam.i4MaxFps = 60000; // UPDATE_PARAMS(cam3aParam.u4AfMode, eMapFocusMode, CameraParameters::KEY_FOCUS_MODE); UPDATE_PARAMS(cam3aParam.u4AwbMode, eMapWhiteBalance, CameraParameters::KEY_WHITE_BALANCE); UPDATE_PARAMS(cam3aParam.u4SceneMode, eMapScene, CameraParameters::KEY_SCENE_MODE); UPDATE_PARAMS(cam3aParam.u4StrobeMode, eMapFlashMode, CameraParameters::KEY_FLASH_MODE); UPDATE_PARAMS(cam3aParam.u4EffectMode, eMapEffect, CameraParameters::KEY_EFFECT); UPDATE_PARAMS(cam3aParam.u4AntiBandingMode, eMapAntiBanding, CameraParameters::KEY_ANTIBANDING); // cam3aParam.i4ExpIndex = mpParamsMgr->getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); cam3aParam.fExpCompStep = mpParamsMgr->getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP); // // AE lock { String8 const s = mpParamsMgr->getStr(CameraParameters::KEY_AUTO_EXPOSURE_LOCK); cam3aParam.bIsAELock = ( ! s.isEmpty() && s == CameraParameters::TRUE ) ? 1 : 0; } // AWB lock { String8 const s = mpParamsMgr->getStr(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); cam3aParam.bIsAWBLock = ( ! s.isEmpty() && s == CameraParameters::TRUE ) ? 1 : 0; } // AF Focus Areas { String8 const s8Area = mpParamsMgr->getStr(CameraParameters::KEY_FOCUS_AREAS); if ( ! s8Area.isEmpty() ) { MY_LOGD("Focus Areas:%s", s8Area.string()); const int maxNumFocusAreas = mpParamsMgr->getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS); List <camera_area_t> focusAreas; mpParamsMgr->parseCamAreas(s8Area.string(), focusAreas, maxNumFocusAreas); int index = 0; for (List<camera_area_t>::iterator it = focusAreas.begin(); it != focusAreas.end(); it++) { cam3aParam.rFocusAreas.rAreas[index].i4Left = it->left; cam3aParam.rFocusAreas.rAreas[index].i4Top = it->top; cam3aParam.rFocusAreas.rAreas[index].i4Right = it->right; cam3aParam.rFocusAreas.rAreas[index].i4Bottom = it->bottom; cam3aParam.rFocusAreas.rAreas[index].i4Weight = it->weight; index++; } cam3aParam.rFocusAreas.u4Count = focusAreas.size(); } } // AE Metering Areas { String8 const s8Area = mpParamsMgr->getStr(CameraParameters::KEY_METERING_AREAS); if ( ! s8Area.isEmpty() ) { MY_LOGD("Metering Areas:%s", s8Area.string()); const int maxNumMeteringAreas = mpParamsMgr->getInt(CameraParameters::KEY_MAX_NUM_METERING_AREAS); List <camera_area_t> meterAreas; mpParamsMgr->parseCamAreas(s8Area.string(), meterAreas, maxNumMeteringAreas); int index = 0; for (List<camera_area_t>::iterator it = meterAreas.begin(); it != meterAreas.end(); it++) { cam3aParam.rMeteringAreas.rAreas[index].i4Left = it->left; cam3aParam.rMeteringAreas.rAreas[index].i4Top = it->top; cam3aParam.rMeteringAreas.rAreas[index].i4Right = it->right; cam3aParam.rMeteringAreas.rAreas[index].i4Bottom = it->bottom; cam3aParam.rMeteringAreas.rAreas[index].i4Weight = it->weight; index++; } cam3aParam.rMeteringAreas.u4Count = meterAreas.size(); } } // MTK DEFINITION CATEGORY UPDATE_PARAMS(cam3aParam.u4AeMode, eMapExpMode, MtkCameraParameters::KEY_SCENE_MODE); UPDATE_PARAMS(cam3aParam.u4IsoSpeedMode, eMapIso, MtkCameraParameters::KEY_ISO_SPEED); UPDATE_PARAMS(cam3aParam.u4AfLampMode, eMapFocusLamp, MtkCameraParameters::KEY_AF_LAMP_MODE); // UPDATE_PARAMS(cam3aParam.u4BrightnessMode, eMapLevel, MtkCameraParameters::KEY_BRIGHTNESS); UPDATE_PARAMS(cam3aParam.u4SaturationMode, eMapLevel, MtkCameraParameters::KEY_SATURATION); UPDATE_PARAMS(cam3aParam.u4ContrastMode, eMapLevel, MtkCameraParameters::KEY_CONTRAST); UPDATE_PARAMS(cam3aParam.u4EdgeMode, eMapLevel, MtkCameraParameters::KEY_EDGE); UPDATE_PARAMS(cam3aParam.u4HueMode, eMapLevel, MtkCameraParameters::KEY_HUE); // cam3aParam.u4ShotMode = mpParamsMgr->getShotMode(); cam3aParam.u4CamMode = mpParamsMgr->getHalAppMode(); cam3aParam.i4RotateDegree = mpParamsMgr->getInt(MtkCameraParameters::KEY_ROTATION); // if ( ! p3AHal->setParams(cam3aParam) ) { MY_LOGE("setParams fail"); ret = INVALID_OPERATION; goto lbExit; } lbExit: p3AHal->destroyInstance(); MY_LOGD("-"); return ret; }
static void CameraMetadata_dump(JNIEnv *env, jobject thiz) { ALOGV("%s", __FUNCTION__); CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); if (metadata == NULL) { return; } /* * Create a socket pair for local streaming read/writes. * * The metadata will be dumped into the write side, * and then read back out (and logged) via the read side. */ int writeFd, readFd; { int sv[2]; if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Failed to create socketpair (errno = %#x, message = '%s')", errno, strerror(errno)); return; } writeFd = sv[0]; readFd = sv[1]; } /* * Create a thread for doing the writing. * * The reading and writing must be concurrent, otherwise * the write will block forever once it exhausts the capped * buffer size (from getsockopt). */ pthread_t writeThread; DumpMetadataParams params = { writeFd, metadata }; { int threadRet = pthread_create(&writeThread, /*attr*/NULL, CameraMetadata_writeMetadataThread, (void*)¶ms); if (threadRet != 0) { close(writeFd); jniThrowExceptionFmt(env, "java/io/IOException", "Failed to create thread for writing (errno = %#x, message = '%s')", threadRet, strerror(threadRet)); } } /* * Read out a byte until stream is complete. Write completed lines * to ALOG. */ { char out[] = {'\0', '\0'}; // large enough to append as a string String8 logLine; // Read one byte at a time! Very slow but avoids complicated \n scanning. ssize_t res; while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) { if (out[0] == '\n') { ALOGD("%s", logLine.string()); logLine.clear(); } else { logLine.append(out); } } if (res < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Failed to read from fd (errno = %#x, message = '%s')", errno, strerror(errno)); //return; } else if (!logLine.isEmpty()) { ALOGD("%s", logLine.string()); } } int res; // Join until thread finishes. Ensures params/metadata is valid until then. if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) { ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')", __FUNCTION__, res, strerror(res)); } }
String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, const String8& name, InputDeviceConfigurationFileType type) { return name.isEmpty() ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) : getInputDeviceConfigurationFilePathByName(name, type); }
int doDump(Bundle* bundle) { status_t result = UNKNOWN_ERROR; if (bundle->getFileSpecCount() < 1) { fprintf(stderr, "ERROR: no dump option specified\n"); return 1; } if (bundle->getFileSpecCount() < 2) { fprintf(stderr, "ERROR: no dump file specified\n"); return 1; } const char* option = bundle->getFileSpecEntry(0); const char* filename = bundle->getFileSpecEntry(1); AssetManager assets; int32_t assetsCookie; if (!assets.addAssetPath(String8(filename), &assetsCookie)) { fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); return 1; } // Make a dummy config for retrieving resources... we need to supply // non-default values for some configs so that we can retrieve resources // in the app that don't have a default. The most important of these is // the API version because key resources like icons will have an implicit // version if they are using newer config types like density. ResTable_config config; memset(&config, 0, sizeof(ResTable_config)); config.language[0] = 'e'; config.language[1] = 'n'; config.country[0] = 'U'; config.country[1] = 'S'; config.orientation = ResTable_config::ORIENTATION_PORT; config.density = ResTable_config::DENSITY_MEDIUM; config.sdkVersion = 10000; // Very high. config.screenWidthDp = 320; config.screenHeightDp = 480; config.smallestScreenWidthDp = 320; config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL; assets.setConfiguration(config); const ResTable& res = assets.getResources(false); if (res.getError() != NO_ERROR) { fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n"); return 1; } // The dynamicRefTable can be null if there are no resources for this asset cookie. // This fine. const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie); Asset* asset = NULL; if (strcmp("resources", option) == 0) { #ifndef __ANDROID__ res.print(bundle->getValues()); #endif } else if (strcmp("strings", option) == 0) { const ResStringPool* pool = res.getTableStringBlock(0); printStringPool(pool); } else if (strcmp("xmltree", option) == 0) { if (bundle->getFileSpecCount() < 3) { fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); goto bail; } for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); ResXMLTree tree(dynamicRefTable); asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; } if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); goto bail; } tree.restart(); printXMLBlock(&tree); tree.uninit(); delete asset; asset = NULL; } } else if (strcmp("xmlstrings", option) == 0) { if (bundle->getFileSpecCount() < 3) { fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); goto bail; } for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; } ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); goto bail; } printStringPool(&tree.getStrings()); delete asset; asset = NULL; } } else { asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); goto bail; } ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); goto bail; } tree.restart(); if (strcmp("permissions", option) == 0) { size_t len; ResXMLTree::event_code_t code; int depth = 0; while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; continue; } if (code != ResXMLTree::START_TAG) { continue; } depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); goto bail; } String8 tag(ctag16); //printf("Depth %d tag %s\n", depth, tag.string()); if (depth == 1) { if (tag != "manifest") { fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); goto bail; } String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string()); } else if (depth == 2 && tag == "permission") { String8 error; String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; } printf("permission: %s\n", ResTable::normalizeForOutput(name.string()).string()); } else if (depth == 2 && tag == "uses-permission") { String8 error; String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; } printUsesPermission(name, AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR)); } } } else if (strcmp("badging", option) == 0) { Vector<String8> locales; res.getLocales(&locales); Vector<ResTable_config> configs; res.getConfigurations(&configs); SortedVector<int> densities; const size_t NC = configs.size(); for (size_t i=0; i<NC; i++) { int dens = configs[i].density; if (dens == 0) { dens = 160; } densities.add(dens); } size_t len; ResXMLTree::event_code_t code; int depth = 0; String8 error; bool withinActivity = false; bool isMainActivity = false; bool isLauncherActivity = false; bool isLeanbackLauncherActivity = false; bool isSearchable = false; bool withinApplication = false; bool withinSupportsInput = false; bool withinFeatureGroup = false; bool withinReceiver = false; bool withinService = false; bool withinProvider = false; bool withinIntentFilter = false; bool hasMainActivity = false; bool hasOtherActivities = false; bool hasOtherReceivers = false; bool hasOtherServices = false; bool hasIntentFilter = false; bool hasWallpaperService = false; bool hasImeService = false; bool hasAccessibilityService = false; bool hasPrintService = false; bool hasWidgetReceivers = false; bool hasDeviceAdminReceiver = false; bool hasPaymentService = false; bool hasDocumentsProvider = false; bool hasCameraActivity = false; bool hasCameraSecureActivity = false; bool hasLauncher = false; bool hasNotificationListenerService = false; bool hasDreamService = false; bool actMainActivity = false; bool actWidgetReceivers = false; bool actDeviceAdminEnabled = false; bool actImeService = false; bool actWallpaperService = false; bool actAccessibilityService = false; bool actPrintService = false; bool actHostApduService = false; bool actOffHostApduService = false; bool actDocumentsProvider = false; bool actNotificationListenerService = false; bool actDreamService = false; bool actCamera = false; bool actCameraSecure = false; bool catLauncher = false; bool hasMetaHostPaymentCategory = false; bool hasMetaOffHostPaymentCategory = false; // These permissions are required by services implementing services // the system binds to (IME, Accessibility, PrintServices, etc.) bool hasBindDeviceAdminPermission = false; bool hasBindInputMethodPermission = false; bool hasBindAccessibilityServicePermission = false; bool hasBindPrintServicePermission = false; bool hasBindNfcServicePermission = false; bool hasRequiredSafAttributes = false; bool hasBindNotificationListenerServicePermission = false; bool hasBindDreamServicePermission = false; // These two implement the implicit permissions that are granted // to pre-1.6 applications. bool hasWriteExternalStoragePermission = false; bool hasReadPhoneStatePermission = false; // If an app requests write storage, they will also get read storage. bool hasReadExternalStoragePermission = false; // Implement transition to read and write call log. bool hasReadContactsPermission = false; bool hasWriteContactsPermission = false; bool hasReadCallLogPermission = false; bool hasWriteCallLogPermission = false; // If an app declares itself as multiArch, we report the // native libraries differently. bool hasMultiArch = false; // This next group of variables is used to implement a group of // backward-compatibility heuristics necessitated by the addition of // some new uses-feature constants in 2.1 and 2.2. In most cases, the // heuristic is "if an app requests a permission but doesn't explicitly // request the corresponding <uses-feature>, presume it's there anyway". // 2.2 also added some other features that apps can request, but that // have no corresponding permission, so we cannot implement any // back-compatibility heuristic for them. The below are thus unnecessary // (but are retained here for documentary purposes.) //bool specCompassFeature = false; //bool specAccelerometerFeature = false; //bool specProximityFeature = false; //bool specAmbientLightFeature = false; //bool specLiveWallpaperFeature = false; int targetSdk = 0; int smallScreen = 1; int normalScreen = 1; int largeScreen = 1; int xlargeScreen = 1; int anyDensity = 1; int requiresSmallestWidthDp = 0; int compatibleWidthLimitDp = 0; int largestWidthLimitDp = 0; String8 pkg; String8 activityName; String8 activityLabel; String8 activityIcon; String8 activityBanner; String8 receiverName; String8 serviceName; Vector<String8> supportedInput; FeatureGroup commonFeatures; Vector<FeatureGroup> featureGroups; KeyedVector<String8, ImpliedFeature> impliedFeatures; while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::END_TAG) { depth--; if (depth < 2) { if (withinSupportsInput && !supportedInput.isEmpty()) { printf("supports-input: '"); const size_t N = supportedInput.size(); for (size_t i=0; i<N; i++) { printf("%s", ResTable::normalizeForOutput( supportedInput[i].string()).string()); if (i != N - 1) { printf("' '"); } else { printf("'\n"); } } supportedInput.clear(); } withinApplication = false; withinSupportsInput = false; withinFeatureGroup = false; } else if (depth < 3) { if (withinActivity && isMainActivity) { String8 aName(getComponentName(pkg, activityName)); if (isLauncherActivity) { printf("launchable-activity:"); if (aName.length() > 0) { printf(" name='%s' ", ResTable::normalizeForOutput(aName.string()).string()); } printf(" label='%s' icon='%s'\n", ResTable::normalizeForOutput(activityLabel.string()).string(), ResTable::normalizeForOutput(activityIcon.string()).string()); } if (isLeanbackLauncherActivity) { printf("leanback-launchable-activity:"); if (aName.length() > 0) { printf(" name='%s' ", ResTable::normalizeForOutput(aName.string()).string()); } printf(" label='%s' icon='%s' banner='%s'\n", ResTable::normalizeForOutput(activityLabel.string()).string(), ResTable::normalizeForOutput(activityIcon.string()).string(), ResTable::normalizeForOutput(activityBanner.string()).string()); } } if (!hasIntentFilter) { hasOtherActivities |= withinActivity; hasOtherReceivers |= withinReceiver; hasOtherServices |= withinService; } else { if (withinService) { hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory && hasBindNfcServicePermission); hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory && hasBindNfcServicePermission); } } withinActivity = false; withinService = false; withinReceiver = false; withinProvider = false; hasIntentFilter = false; isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false; } else if (depth < 4) { if (withinIntentFilter) { if (withinActivity) { hasMainActivity |= actMainActivity; hasLauncher |= catLauncher; hasCameraActivity |= actCamera; hasCameraSecureActivity |= actCameraSecure; hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure; } else if (withinReceiver) { hasWidgetReceivers |= actWidgetReceivers; hasDeviceAdminReceiver |= (actDeviceAdminEnabled && hasBindDeviceAdminPermission); hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled); } else if (withinService) { hasImeService |= actImeService; hasWallpaperService |= actWallpaperService; hasAccessibilityService |= (actAccessibilityService && hasBindAccessibilityServicePermission); hasPrintService |= (actPrintService && hasBindPrintServicePermission); hasNotificationListenerService |= actNotificationListenerService && hasBindNotificationListenerServicePermission; hasDreamService |= actDreamService && hasBindDreamServicePermission; hasOtherServices |= (!actImeService && !actWallpaperService && !actAccessibilityService && !actPrintService && !actHostApduService && !actOffHostApduService && !actNotificationListenerService); } else if (withinProvider) { hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes; } } withinIntentFilter = false; } continue; } if (code != ResXMLTree::START_TAG) { continue; } depth++; const char16_t* ctag16 = tree.getElementName(&len); if (ctag16 == NULL) { fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); goto bail; } String8 tag(ctag16); //printf("Depth %d, %s\n", depth, tag.string()); if (depth == 1) { if (tag != "manifest") { fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); goto bail; } pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: name='%s' ", ResTable::normalizeForOutput(pkg.string()).string()); int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); goto bail; } if (versionCode > 0) { printf("versionCode='%d' ", versionCode); } else { printf("versionCode='' "); } String8 versionName = AaptXml::getResolvedAttribute(res, tree, VERSION_NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); goto bail; } printf("versionName='%s'", ResTable::normalizeForOutput(versionName.string()).string()); String8 splitName = AaptXml::getAttribute(tree, NULL, "split"); if (!splitName.isEmpty()) { printf(" split='%s'", ResTable::normalizeForOutput( splitName.string()).string()); } String8 platformVersionName = AaptXml::getAttribute(tree, NULL, "platformBuildVersionName"); printf(" platformBuildVersionName='%s'", platformVersionName.string()); printf("\n"); int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree, INSTALL_LOCATION_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n", error.string()); goto bail; } if (installLocation >= 0) { printf("install-location:'"); switch (installLocation) { case 0: printf("auto"); break; case 1: printf("internalOnly"); break; case 2: printf("preferExternal"); break; default: fprintf(stderr, "Invalid installLocation %d\n", installLocation); goto bail; } printf("'\n"); } } else if (depth == 2) { withinApplication = false; if (tag == "application") {
int main(int argc, char* const argv[]) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); } if (!LOG_NDEBUG) { String8 argv_String; for (int i = 0; i < argc; ++i) { argv_String.append("\""); argv_String.append(argv[i]); argv_String.append("\" "); } ALOGV("app_process main with argv: %s", argv_String.string()); } AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. // // As an exception to the above rule, anything in "spaced commands" // goes to the vm even though it has a space in it. const char* spaced_commands[] = { "-cp", "-classpath" }; // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). bool known_command = false; int i; for (i = 0; i < argc; i++) { if (known_command == true) { runtime.addOption(strdup(argv[i])); ALOGV("app_process main add known option '%s'", argv[i]); known_command = false; continue; } for (int j = 0; j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0])); ++j) { if (strcmp(argv[i], spaced_commands[j]) == 0) { known_command = true; ALOGV("app_process main found known command '%s'", argv[i]); } } if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); ALOGV("app_process main add option '%s'", argv[i]); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } Vector<String8> args; if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); if (!LOG_NDEBUG) { String8 restOfArgs; char* const* argv_new = argv + i; int argc_new = argc - i; for (int k = 0; k < argc_new; ++k) { restOfArgs.append("\""); restOfArgs.append(argv_new[k]); restOfArgs.append("\" "); } ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string()); } } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string(), true /* setProcName */); } if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); } }
void *Loader::load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask) { class MatchFile { public: static String8 find(const char* kind) { String8 result; String8 pattern; pattern.appendFormat("lib%s", kind); const char* const searchPaths[] = { #if defined(__LP64__) "/vendor/lib64/egl", "/system/lib64/egl" #else "/vendor/lib/egl", "/system/lib/egl" #endif }; // first, we search for the exact name of the GLES userspace // driver in both locations. // i.e.: // libGLES.so, or: // libEGL.so, libGLESv1_CM.so, libGLESv2.so for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { if (find(result, pattern, searchPaths[i], true)) { return result; } } // for compatibility with the old "egl.cfg" naming convention // we look for files that match: // libGLES_*.so, or: // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so pattern.append("_"); for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { if (find(result, pattern, searchPaths[i], false)) { return result; } } // we didn't find the driver. gah. result.clear(); return result; } private: static bool find(String8& result, const String8& pattern, const char* const search, bool exact) { // in the emulator case, we just return the hardcoded name // of the software renderer. if (checkGlesEmulationStatus() == 0) { ALOGD("Emulator without GPU support detected. " "Fallback to software renderer."); #if defined(__LP64__) result.setTo("/system/lib64/egl/libGLES_android.so"); #else result.setTo("/system/lib/egl/libGLES_android.so"); #endif return true; } if (exact) { String8 absolutePath; absolutePath.appendFormat("%s/%s.so", search, pattern.string()); if (!access(absolutePath.string(), R_OK)) { result = absolutePath; return true; } return false; } DIR* d = opendir(search); if (d != NULL) { struct dirent cur; struct dirent* e; while (readdir_r(d, &cur, &e) == 0 && e) { if (e->d_type == DT_DIR) { continue; } if (!strcmp(e->d_name, "libGLES_android.so")) { // always skip the software renderer continue; } if (strstr(e->d_name, pattern.string()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { result.clear(); result.appendFormat("%s/%s", search, e->d_name); closedir(d); return true; } } } closedir(d); } return false; } }; String8 absolutePath = MatchFile::find(kind); if (absolutePath.isEmpty()) { // this happens often, we don't want to log an error return 0; } const char* const driver_absolute_path = absolutePath.string(); void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); if (dso == 0) { const char* err = dlerror(); ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown"); return 0; } ALOGD("loaded %s", driver_absolute_path); if (mask & EGL) { getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress"); ALOGE_IF(!getProcAddress, "can't find eglGetProcAddress() in %s", driver_absolute_path); egl_t* egl = &cnx->egl; __eglMustCastToProperFunctionPointerType* curr = (__eglMustCastToProperFunctionPointerType*)egl; char const * const * api = egl_names; while (*api) { char const * name = *api; __eglMustCastToProperFunctionPointerType f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, name); if (f == NULL) { // couldn't find the entry-point, use eglGetProcAddress() f = getProcAddress(name); if (f == NULL) { f = (__eglMustCastToProperFunctionPointerType)0; } } *curr++ = f; api++; } } if (mask & GLESv1_CM) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl, getProcAddress); } if (mask & GLESv2) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl, getProcAddress); } return dso; }
status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel, /*out*/ sp<VendorTagDescriptor>& descriptor) { status_t res = OK; if (parcel == NULL) { ALOGE("%s: parcel argument was NULL.", __FUNCTION__); return BAD_VALUE; } int32_t tagCount = 0; if ((res = parcel->readInt32(&tagCount)) != OK) { ALOGE("%s: could not read tag count from parcel", __FUNCTION__); return res; } if (tagCount < 0 || tagCount > INT32_MAX) { ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); return BAD_VALUE; } sp<VendorTagDescriptor> desc = new VendorTagDescriptor(); desc->mTagCount = tagCount; uint32_t tag, sectionIndex; uint32_t maxSectionIndex = 0; int32_t tagType; Vector<uint32_t> allTags; for (int32_t i = 0; i < tagCount; ++i) { if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&tag))) != OK) { ALOGE("%s: could not read tag id from parcel for index %d", __FUNCTION__, i); break; } if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); res = BAD_VALUE; break; } if ((res = parcel->readInt32(&tagType)) != OK) { ALOGE("%s: could not read tag type from parcel for tag %d", __FUNCTION__, tag); break; } if (tagType < 0 || tagType >= NUM_TYPES) { ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); res = BAD_VALUE; break; } String8 tagName = parcel->readString8(); if (tagName.isEmpty()) { ALOGE("%s: parcel tag name was NULL for tag %d.", __FUNCTION__, tag); res = NOT_ENOUGH_DATA; break; } if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(§ionIndex))) != OK) { ALOGE("%s: could not read section index for tag %d.", __FUNCTION__, tag); break; } maxSectionIndex = (maxSectionIndex >= sectionIndex) ? maxSectionIndex : sectionIndex; allTags.add(tag); desc->mTagToNameMap.add(tag, tagName); desc->mTagToSectionMap.add(tag, sectionIndex); desc->mTagToTypeMap.add(tag, tagType); } if (res != OK) { return res; } size_t sectionCount; if (tagCount > 0) { if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(§ionCount))) != OK) { ALOGE("%s: could not read section count for.", __FUNCTION__); return res; } if (sectionCount < (maxSectionIndex + 1)) { ALOGE("%s: Incorrect number of sections defined, received %zu, needs %d.", __FUNCTION__, sectionCount, (maxSectionIndex + 1)); return BAD_VALUE; } LOG_ALWAYS_FATAL_IF(desc->mSections.setCapacity(sectionCount) <= 0, "Vector capacity must be positive"); for (size_t i = 0; i < sectionCount; ++i) { String8 sectionName = parcel->readString8(); if (sectionName.isEmpty()) { ALOGE("%s: parcel section name was NULL for section %zu.", __FUNCTION__, i); return NOT_ENOUGH_DATA; } desc->mSections.add(sectionName); } } LOG_ALWAYS_FATAL_IF(static_cast<size_t>(tagCount) != allTags.size(), "tagCount must be the same as allTags size"); // Set up reverse mapping for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { uint32_t tag = allTags[i]; String8 sectionString = desc->mSections[desc->mTagToSectionMap.valueFor(tag)]; ssize_t reverseIndex = -1; if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) { KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>(); reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper); } desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag); } descriptor = desc; return res; }
void StagefrightMetadataRetriever::parseMetaData() { sp<MetaData> meta = mExtractor->getMetaData(); if (meta == NULL) { ALOGV("extractor doesn't publish metadata, failed to initialize?"); return; } struct Map { int from; int to; }; static const Map kMap[] = { { kKeyMIMEType, METADATA_KEY_MIMETYPE }, { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER }, { kKeyAlbum, METADATA_KEY_ALBUM }, { kKeyArtist, METADATA_KEY_ARTIST }, { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST }, { kKeyAuthor, METADATA_KEY_AUTHOR }, { kKeyComposer, METADATA_KEY_COMPOSER }, { kKeyDate, METADATA_KEY_DATE }, { kKeyGenre, METADATA_KEY_GENRE }, { kKeyTitle, METADATA_KEY_TITLE }, { kKeyYear, METADATA_KEY_YEAR }, { kKeyWriter, METADATA_KEY_WRITER }, { kKeyCompilation, METADATA_KEY_COMPILATION }, { kKeyLocation, METADATA_KEY_LOCATION }, }; static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); for (size_t i = 0; i < kNumMapEntries; ++i) { const char *value; if (meta->findCString(kMap[i].from, &value)) { mMetaData.add(kMap[i].to, String8(value)); } } const void *data; uint32_t type; size_t dataSize; if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize) && mAlbumArt == NULL) { mAlbumArt = new MediaAlbumArt; mAlbumArt->mSize = dataSize; mAlbumArt->mData = new uint8_t[dataSize]; memcpy(mAlbumArt->mData, data, dataSize); } size_t numTracks = mExtractor->countTracks(); char tmp[32]; sprintf(tmp, "%d", numTracks); mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); bool hasAudio = false; bool hasVideo = false; int32_t videoWidth = -1; int32_t videoHeight = -1; int32_t audioBitrate = -1; int32_t rotationAngle = -1; // The overall duration is the duration of the longest track. int64_t maxDurationUs = 0; String8 timedTextLang; for (size_t i = 0; i < numTracks; ++i) { sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); int64_t durationUs; if (trackMeta->findInt64(kKeyDuration, &durationUs)) { if (durationUs > maxDurationUs) { maxDurationUs = durationUs; } } const char *mime; if (trackMeta->findCString(kKeyMIMEType, &mime)) { if (!hasAudio && !strncasecmp("audio/", mime, 6)) { hasAudio = true; if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) { audioBitrate = -1; } } else if (!hasVideo && !strncasecmp("video/", mime, 6)) { hasVideo = true; CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth)); CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight)); if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) { rotationAngle = 0; } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { const char *lang; bool success = trackMeta->findCString(kKeyMediaLanguage, &lang); if (success) { timedTextLang.append(String8(lang)); timedTextLang.append(String8(":")); } else { ALOGE("No language found for timed text"); } } } } // To save the language codes for all timed text tracks // If multiple text tracks present, the format will look // like "eng:chi" if (!timedTextLang.isEmpty()) { mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang); } // The duration value is a string representing the duration in ms. sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); if (hasAudio) { mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes")); } if (hasVideo) { mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes")); sprintf(tmp, "%d", videoWidth); mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp)); sprintf(tmp, "%d", videoHeight); mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp)); sprintf(tmp, "%d", rotationAngle); mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp)); } if (numTracks == 1 && hasAudio && audioBitrate >= 0) { sprintf(tmp, "%d", audioBitrate); mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); } else { off64_t sourceSize; if (mSource->getSize(&sourceSize) == OK) { int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs); sprintf(tmp, "%lld", avgBitRate); mMetaData.add(METADATA_KEY_BITRATE, String8(tmp)); } } if (numTracks == 1) { const char *fileMIME; CHECK(meta->findCString(kKeyMIMEType, &fileMIME)); if (!strcasecmp(fileMIME, "video/x-matroska")) { sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0); const char *trackMIME; CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); if (!strncasecmp("audio/", trackMIME, 6)) { // The matroska file only contains a single audio track, // rewrite its mime type. mMetaData.add( METADATA_KEY_MIMETYPE, String8("audio/x-matroska")); } } } // To check whether the media file is drm-protected if (mExtractor->getDrmFlag()) { mMetaData.add(METADATA_KEY_IS_DRM, String8("1")); } }
bool isWVM(const char* url, const KeyedVector<String8, String8> *headers) { sp<DataSource> dataSource; String8 mUri; KeyedVector<String8, String8> mUriHeaders; sp<HTTPBase> mConnectingDataSource; sp<NuCachedSource2> mCachedSource; uint32_t mFlags; mUri = url; void *VendorLibHandle = NULL; if (VendorLibHandle == NULL) { VendorLibHandle = dlopen("libwvm.so", RTLD_NOW); } if (!VendorLibHandle) { return false; } if (headers) { mUriHeaders = *headers; ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); if (index >= 0) { // Browser is in "incognito" mode, suppress logging URLs. // This isn't something that should be passed to the server. mUriHeaders.removeItemsAt(index); mFlags |= INCOGNITO; } } if (!strncasecmp("http://", mUri.string(), 7) || !strncasecmp("https://", mUri.string(), 8)) { mConnectingDataSource = HTTPBase::Create( (mFlags & INCOGNITO) ? HTTPBase::kFlagIncognito : 0); String8 cacheConfig; bool disconnectAtHighwatermark; NuCachedSource2::RemoveCacheSpecificHeaders( &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); if (err != OK) { mConnectingDataSource.clear(); ALOGI("mConnectingDataSource->connect() returned %d", err); return false; } // The widevine extractor does its own caching. mCachedSource = new NuCachedSource2( mConnectingDataSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); dataSource = mCachedSource; mConnectingDataSource.clear(); // Removed prefill as we can't abort it. // // We're going to prefill the cache before trying to instantiate // the extractor below, as the latter is an operation that otherwise // could block on the datasource for a significant amount of time. // During that time we'd be unable to abort the preparation phase // without this prefill. } else { dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); } if (dataSource == NULL) { return false; } typedef WVMLoadableExtractor *(*SnifferFunc)(const sp<DataSource>&); SnifferFunc snifferFunc = (SnifferFunc) dlsym(VendorLibHandle, "_ZN7android15IsWidevineMediaERKNS_2spINS_10DataSourceEEE"); if (snifferFunc) { if ((*snifferFunc)(dataSource)) { return true; } } return false; }
int main(int argc, char* const argv[]) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return // EINVAL. Don't die on such kernels. if (errno != EINVAL) { LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); return 12; } } if (xposed::handleOptions(argc, argv)) return 0; AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } Vector<String8> args; if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } isXposedLoaded = xposed::initialize(zygote, startSystemServer, className, argc, argv); if (zygote) { runtimeStart(runtime, isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : "com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtimeStart(runtime, isXposedLoaded ? XPOSED_CLASS_DOTS_TOOLS : "com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } }
// static sp<DataSource> DataSource::CreateFromURI( const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers, String8 *contentType, HTTPBase *httpSource) { if (contentType != NULL) { *contentType = ""; } bool isWidevine = !strncasecmp("widevine://", uri, 11); sp<DataSource> source; if (!strncasecmp("file://", uri, 7)) { source = new FileSource(uri + 7); } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8) || isWidevine) { if (httpService == NULL) { ALOGE("Invalid http service!"); return NULL; } if (httpSource == NULL) { sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection(); if (conn == NULL) { ALOGE("Failed to make http connection from http service!"); return NULL; } httpSource = new MediaHTTP(conn); } String8 tmp; if (isWidevine) { tmp = String8("http://"); tmp.append(uri + 11); uri = tmp.string(); } String8 cacheConfig; bool disconnectAtHighwatermark; KeyedVector<String8, String8> nonCacheSpecificHeaders; if (headers != NULL) { nonCacheSpecificHeaders = *headers; NuCachedSource2::RemoveCacheSpecificHeaders( &nonCacheSpecificHeaders, &cacheConfig, &disconnectAtHighwatermark); } if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) { ALOGE("Failed to connect http source!"); return NULL; } if (!isWidevine) { if (contentType != NULL) { *contentType = httpSource->getMIMEType(); } source = new NuCachedSource2( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); } else { // We do not want that prefetching, caching, datasource wrapper // in the widevine:// case. source = httpSource; } } else if (!strncasecmp("data:", uri, 5)) { source = DataURISource::Create(uri); } else { // Assume it's a filename. source = new FileSource(uri); } if (source == NULL || source->initCheck() != OK) { return NULL; } return source; }