bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */) { bool bReturn(true); ADDON::VECADDONS map; { CSingleLock lock(m_critSection); map = m_addons; } for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++) { const AddonPtr clientAddon = map.at(iClientPtr); if (!clientAddon->Enabled() && IsKnownClient(clientAddon)) { /* stop the client and remove it from the db */ bReturn &= StopClient(clientAddon, false) && bReturn; } else if (clientAddon->Enabled() && (bInitialiseAllClients || !IsKnownClient(clientAddon))) { /* register the new client and initialise it */ bReturn &= InitialiseClient(clientAddon) && bReturn; } } /* check whether all clients are (still) connected */ { CSingleLock lock(m_critSection); m_bAllClientsConnected = (ConnectedClientAmount() == EnabledClientAmount()); } return bReturn; }
bool CPVRClients::UpdateAddons(void) { ADDON::VECADDONS addons; bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true)); if (bReturn) { CSingleLock lock(m_critSection); m_addons = addons; } // handle "new" addons which aren't yet in the db - these have to be added first for (unsigned iClientPtr = 0; iClientPtr < m_addons.size(); iClientPtr++) { const AddonPtr clientAddon = m_addons.at(iClientPtr); if (!m_addonDb.HasAddon(clientAddon->ID())) { m_addonDb.AddAddon(clientAddon, -1); } } if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed && !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) && (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting)) { // No PVR add-ons could be found // You need a tuner, backend software, and an add-on for the backend to be able to use PVR. // Please visit xbmc.org/pvr to learn more. m_bNoAddonWarningDisplayed = true; g_guiSettings.SetBool("pvrmanager.enabled", false); CGUIDialogOK::ShowAndGetInput(19271, 19272, 19273, 19274); CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_MYPVR, 0); g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_MYPVR); } return bReturn; }
bool CPVRClients::UpdateAddons(void) { ADDON::VECADDONS addons; bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true)); if (bReturn) { CSingleLock lock(m_critSection); m_addons = addons; } if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed && !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) && (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting)) { // No PVR add-ons could be found // You need a tuner, backend software, and an add-on for the backend to be able to use PVR. // Please visit xbmc.org/pvr to learn more. m_bNoAddonWarningDisplayed = true; CGUIDialogOK::ShowAndGetInput(19271, 19272, 19273, 19274); } return bReturn; }
bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */) { bool bReturn(true); ADDON::VECADDONS map; ADDON::VECADDONS disableAddons; { CSingleLock lock(m_critSection); map = m_addons; } if (map.size() == 0) return false; for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++) { const AddonPtr clientAddon = map.at(iClientPtr); bool bEnabled = clientAddon->Enabled() && !m_addonDb.IsAddonDisabled(clientAddon->ID()); if (!bEnabled && IsKnownClient(clientAddon)) { CSingleLock lock(m_critSection); /* stop the client and remove it from the db */ StopClient(clientAddon, false); ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), clientAddon); if (addonPtr != m_addons.end()) m_addons.erase(addonPtr); } else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(clientAddon) || !IsConnectedClient(clientAddon))) { bool bDisabled(false); // register the add-on in the pvr db, and create the CPVRClient instance int iClientId = RegisterClient(clientAddon); if (iClientId < 0) { // failed to register or create the add-on, disable it CLog::Log(LOGWARNING, "%s - failed to register add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } else { ADDON_STATUS status(ADDON_STATUS_UNKNOWN); PVR_CLIENT addon; { CSingleLock lock(m_critSection); if (!GetClient(iClientId, addon)) { CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } } // throttle connection attempts, no more than 1 attempt per 5 seconds if (!bDisabled && addon->Enabled()) { time_t now; CDateTime::GetCurrentDateTime().GetAsTime(now); std::map<int, time_t>::iterator it = m_connectionAttempts.find(iClientId); if (it != m_connectionAttempts.end() && now < it->second) continue; m_connectionAttempts[iClientId] = now + 5; } // re-check the enabled status. newly installed clients get disabled when they're added to the db if (!bDisabled && addon->Enabled() && (status = addon->Create(iClientId)) != ADDON_STATUS_OK) { CLog::Log(LOGWARNING, "%s - failed to create add-on %s, status = %d", __FUNCTION__, clientAddon->Name().c_str(), status); if (!addon.get() || !addon->DllLoaded() || status == ADDON_STATUS_PERMANENT_FAILURE) { // failed to load the dll of this add-on, disable it CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } } } if (bDisabled && (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting)) CGUIDialogOK::ShowAndGetInput(24070, 24071, 16029, 0); } } // disable add-ons that failed to initialise if (disableAddons.size() > 0) { CSingleLock lock(m_critSection); for (ADDON::VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); it++) { // disable in the add-on db m_addonDb.DisableAddon((*it)->ID(), true); // remove from the pvr add-on list ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), *it); if (addonPtr != m_addons.end()) m_addons.erase(addonPtr); } } return bReturn; }
bool CPythonInvoker::execute(const std::string &script, const std::vector<std::string> &arguments) { // copy the code/script into a local string buffer m_sourceFile = script; // copy the arguments into a local buffer m_argc = arguments.size(); m_argv = new char*[m_argc]; for (unsigned int i = 0; i < m_argc; i++) { m_argv[i] = new char[arguments.at(i).length() + 1]; strcpy(m_argv[i], arguments.at(i).c_str()); } CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): start processing", GetId(), m_sourceFile.c_str()); int m_Py_file_input = Py_file_input; // get the global lock PyEval_AcquireLock(); PyThreadState* state = Py_NewInterpreter(); if (state == NULL) { PyEval_ReleaseLock(); CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): FAILED to get thread state!", GetId(), m_sourceFile.c_str()); return false; } // swap in my thread state PyThreadState_Swap(state); XBMCAddon::AddonClass::Ref<XBMCAddon::Python::PythonLanguageHook> languageHook(new XBMCAddon::Python::PythonLanguageHook(state->interp)); languageHook->RegisterMe(); onInitialization(); setState(InvokerStateInitialized); std::string realFilename(CSpecialProtocol::TranslatePath(m_sourceFile)); if (realFilename == m_sourceFile) CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): the source file to load is \"%s\"", GetId(), m_sourceFile.c_str(), m_sourceFile.c_str()); else CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): the source file to load is \"%s\" (\"%s\")", GetId(), m_sourceFile.c_str(), m_sourceFile.c_str(), realFilename.c_str()); // get path from script file name and add python path's // this is used for python so it will search modules from script path first std::string scriptDir = URIUtils::GetDirectory(realFilename); URIUtils::RemoveSlashAtEnd(scriptDir); addPath(scriptDir); // add all addon module dependecies to path if (m_addon) { std::set<std::string> paths; getAddonModuleDeps(m_addon, paths); for (std::set<std::string>::const_iterator it = paths.begin(); it != paths.end(); ++it) addPath(*it); } else { // for backwards compatibility. // we don't have any addon so just add all addon modules installed CLog::Log(LOGWARNING, "CPythonInvoker(%d): Script invoked without an addon. Adding all addon " "modules installed to python path as fallback. This behaviour will be removed in future " "version.", GetId()); ADDON::VECADDONS addons; ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons); for (unsigned int i = 0; i < addons.size(); ++i) addPath(CSpecialProtocol::TranslatePath(addons[i]->LibPath())); } // we want to use sys.path so it includes site-packages // if this fails, default to using Py_GetPath PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete if (pathObj != NULL && PyList_Check(pathObj)) { for (int i = 0; i < PyList_Size(pathObj); i++) { PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete if (e != NULL && PyString_Check(e)) addNativePath(PyString_AsString(e)); // returns internal data, don't delete or modify } } else addNativePath(Py_GetPath()); Py_DECREF(sysMod); // release ref to sysMod // set current directory and python's path. if (m_argv != NULL) PySys_SetArgv(m_argc, m_argv); #ifdef TARGET_WINDOWS std::string pyPathUtf8; g_charsetConverter.systemToUtf8(m_pythonPath, pyPathUtf8, false); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): setting the Python path to %s", GetId(), m_sourceFile.c_str(), pyPathUtf8.c_str()); #else // ! TARGET_WINDOWS CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): setting the Python path to %s", GetId(), m_sourceFile.c_str(), m_pythonPath.c_str()); #endif // ! TARGET_WINDOWS PySys_SetPath((char *)m_pythonPath.c_str()); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): entering source directory %s", GetId(), m_sourceFile.c_str(), scriptDir.c_str()); PyObject* module = PyImport_AddModule((char*)"__main__"); PyObject* moduleDict = PyModule_GetDict(module); // when we are done initing we store thread state so we can be aborted PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // we need to check if we was asked to abort before we had inited bool stopping = false; { CSingleLock lock(m_critical); m_threadState = state; stopping = m_stop; } PyEval_AcquireLock(); PyThreadState_Swap(state); bool failed = false; if (!stopping) { try { // run script from file // We need to have python open the file because on Windows the DLL that python // is linked against may not be the DLL that xbmc is linked against so // passing a FILE* to python from an fopen has the potential to crash. std::string nativeFilename(realFilename); // filename in system encoding #ifdef TARGET_WINDOWS if (!g_charsetConverter.utf8ToSystem(nativeFilename, true)) { CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): can't convert filename \"%s\" to system encoding", GetId(), m_sourceFile.c_str(), realFilename.c_str()); return false; } #endif PyObject* file = PyFile_FromString((char *)nativeFilename.c_str(), (char*)"r"); FILE *fp = PyFile_AsFile(file); if (fp != NULL) { PyObject *f = PyString_FromString(nativeFilename.c_str()); PyDict_SetItemString(moduleDict, "__file__", f); onPythonModuleInitialization(moduleDict); Py_DECREF(f); setState(InvokerStateRunning); XBMCAddon::Python::PyContext pycontext; // this is a guard class that marks this callstack as being in a python context PyRun_FileExFlags(fp, nativeFilename.c_str(), m_Py_file_input, moduleDict, moduleDict, 1, NULL); } else CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): %s not found!", GetId(), m_sourceFile.c_str(), m_sourceFile.c_str()); } catch (const XbmcCommons::Exception& e) { setState(InvokerStateFailed); e.LogThrowMessage(); failed = true; } catch (...) { setState(InvokerStateFailed); CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failure in script", GetId(), m_sourceFile.c_str()); failed = true; } } bool systemExitThrown = false; InvokerState stateToSet; if (!failed && !PyErr_Occurred()) { CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script successfully run", GetId(), m_sourceFile.c_str()); stateToSet = InvokerStateDone; onSuccess(); } else if (PyErr_ExceptionMatches(PyExc_SystemExit)) { systemExitThrown = true; CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script aborted", GetId(), m_sourceFile.c_str()); stateToSet = InvokerStateFailed; onAbort(); } else { stateToSet = InvokerStateFailed; // if it failed with an exception we already logged the details if (!failed) { PythonBindings::PythonToCppException e; e.LogThrowMessage(); } onError(); } // no need to do anything else because the script has already stopped if (failed) { setState(stateToSet); return true; } PyObject *m = PyImport_AddModule((char*)"xbmc"); if (m == NULL || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1))) CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to set abortRequested", GetId(), m_sourceFile.c_str()); // make sure all sub threads have finished for (PyThreadState* s = state->interp->tstate_head, *old = NULL; s;) { if (s == state) { s = s->next; continue; } if (old != s) { CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): waiting on thread %" PRIu64, GetId(), m_sourceFile.c_str(), (uint64_t)s->thread_id); old = s; } CPyThreadState pyState; Sleep(100); pyState.Restore(); s = state->interp->tstate_head; } // pending calls must be cleared out XBMCAddon::RetardedAsynchCallbackHandler::clearPendingCalls(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // set stopped event - this allows ::stop to run and kill remaining threads // this event has to be fired without holding m_critical // also the GIL (PyEval_AcquireLock) must not be held // if not obeyed there is still no deadlock because ::stop waits with timeout (smart one!) m_stoppedEvent.Set(); { CSingleLock lock(m_critical); m_threadState = NULL; } PyEval_AcquireLock(); PyThreadState_Swap(state); onDeinitialization(); // run the gc before finishing // // if the script exited by throwing a SystemExit excepton then going back // into the interpreter causes this python bug to get hit: // http://bugs.python.org/issue10582 // and that causes major failures. So we are not going to go back in // to run the GC if that's the case. if (!m_stop && languageHook->HasRegisteredAddonClasses() && !systemExitThrown && PyRun_SimpleString(GC_SCRIPT) == -1) CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to run the gc to clean up after running prior to shutting down the Interpreter", GetId(), m_sourceFile.c_str()); Py_EndInterpreter(state); // If we still have objects left around, produce an error message detailing what's been left behind if (languageHook->HasRegisteredAddonClasses()) CLog::Log(LOGWARNING, "CPythonInvoker(%d, %s): the python script \"%s\" has left several " "classes in memory that we couldn't clean up. The classes include: %s", GetId(), m_sourceFile.c_str(), m_sourceFile.c_str(), getListOfAddonClassesAsString(languageHook).c_str()); // unregister the language hook languageHook->UnregisterMe(); PyEval_ReleaseLock(); setState(stateToSet); return true; }
CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer, const CFileItem &fileitem, bool scanforextaudio) { std::string file = fileitem.GetPath(); if (scanforextaudio) { // find any available external audio tracks std::vector<std::string> filenames; filenames.push_back(file); CUtil::ScanForExternalAudio(file, filenames); CUtil::ScanForExternalDemuxSub(file, filenames); if (filenames.size() >= 2) { return CreateInputStream(pPlayer, fileitem, filenames); } } ADDON::VECADDONS addons; ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(addons, ADDON::ADDON_INPUTSTREAM); for (size_t i=0; i<addons.size(); ++i) { std::shared_ptr<ADDON::CInputStream> input(std::static_pointer_cast<ADDON::CInputStream>(addons[i])); if (input->Supports(fileitem)) { std::shared_ptr<ADDON::CInputStream> addon = input; if (!input->UseParent()) addon = std::shared_ptr<ADDON::CInputStream>(new ADDON::CInputStream(*input)); ADDON_STATUS status = addon->Create(); if (status == ADDON_STATUS_OK) { unsigned int videoWidth, videoHeight; pPlayer->GetVideoResolution(videoWidth, videoHeight); addon->SetVideoResolution(videoWidth, videoHeight); return new CInputStreamAddon(fileitem, addon); } } } if (fileitem.IsDiscImage()) { #ifdef HAVE_LIBBLURAY CURL url("udf://"); url.SetHostName(file); url.SetFileName("BDMV/index.bdmv"); if(XFILE::CFile::Exists(url.Get())) return new CDVDInputStreamBluray(pPlayer, fileitem); #endif return new CDVDInputStreamNavigator(pPlayer, fileitem); } #ifdef HAS_DVD_DRIVE if(file.compare(g_mediaManager.TranslateDevicePath("")) == 0) { #ifdef HAVE_LIBBLURAY if(XFILE::CFile::Exists(URIUtils::AddFileToFolder(file, "BDMV/index.bdmv"))) return new CDVDInputStreamBluray(pPlayer, fileitem); #endif return new CDVDInputStreamNavigator(pPlayer, fileitem); } #endif if (fileitem.IsDVDFile(false, true)) return (new CDVDInputStreamNavigator(pPlayer, fileitem)); else if(file.substr(0, 6) == "pvr://") return new CDVDInputStreamPVRManager(pPlayer, fileitem); #ifdef HAVE_LIBBLURAY else if (fileitem.IsType(".bdmv") || fileitem.IsType(".mpls") || file.substr(0, 7) == "bluray:") return new CDVDInputStreamBluray(pPlayer, fileitem); #endif else if(file.substr(0, 6) == "rtp://" || file.substr(0, 7) == "rtsp://" || file.substr(0, 6) == "sdp://" || file.substr(0, 6) == "udp://" || file.substr(0, 6) == "tcp://" || file.substr(0, 6) == "mms://" || file.substr(0, 7) == "mmst://" || file.substr(0, 7) == "mmsh://") return new CDVDInputStreamFFmpeg(fileitem); #ifdef ENABLE_DVDINPUTSTREAM_STACK else if(file.substr(0, 8) == "stack://") return new CDVDInputStreamStack(fileitem); #endif else if (fileitem.IsInternetStream()) { if (fileitem.IsType(".m3u8")) return new CDVDInputStreamFFmpeg(fileitem); if (fileitem.GetMimeType() == "application/vnd.apple.mpegurl") return new CDVDInputStreamFFmpeg(fileitem); } // our file interface handles all these types of streams return (new CDVDInputStreamFile(fileitem)); }
bool CSystemGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const { switch (info.m_info) { /////////////////////////////////////////////////////////////////////////////////////////////// // SYSTEM_* /////////////////////////////////////////////////////////////////////////////////////////////// case SYSTEM_ALWAYS_TRUE: value = true; return true; case SYSTEM_ALWAYS_FALSE: value = false; return true; case SYSTEM_ETHERNET_LINK_ACTIVE: // wtf: not implementated - always returns true?! value = true; return true; case SYSTEM_PLATFORM_LINUX: #if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_WINDOWS: #ifdef TARGET_WINDOWS value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_UWP: #ifdef TARGET_WINDOWS_STORE value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_DARWIN: #ifdef TARGET_DARWIN value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_DARWIN_OSX: #ifdef TARGET_DARWIN_OSX value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_DARWIN_IOS: #ifdef TARGET_DARWIN_IOS value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_ANDROID: #if defined(TARGET_ANDROID) value = true; #else value = false; #endif return true; case SYSTEM_PLATFORM_LINUX_RASPBERRY_PI: #if defined(TARGET_RASPBERRY_PI) value = true; #else value = false; #endif return true; case SYSTEM_MEDIA_DVD: value = g_mediaManager.IsDiscInDrive(); return true; case SYSTEM_MEDIA_AUDIO_CD: #ifdef HAS_DVD_DRIVE if (g_mediaManager.IsDiscInDrive()) { MEDIA_DETECT::CCdInfo *pCdInfo = g_mediaManager.GetCdInfo(); value = pCdInfo && (pCdInfo->IsAudio(1) || pCdInfo->IsCDExtra(1) || pCdInfo->IsMixedMode(1)); } else #endif { value = false; } return true; #ifdef HAS_DVD_DRIVE case SYSTEM_DVDREADY: value = g_mediaManager.GetDriveStatus() != DRIVE_NOT_READY; return true; case SYSTEM_TRAYOPEN: value = g_mediaManager.GetDriveStatus() == DRIVE_OPEN; return true; #endif case SYSTEM_CAN_POWERDOWN: value = CServiceBroker::GetPowerManager().CanPowerdown(); return true; case SYSTEM_CAN_SUSPEND: value = CServiceBroker::GetPowerManager().CanSuspend(); return true; case SYSTEM_CAN_HIBERNATE: value = CServiceBroker::GetPowerManager().CanHibernate(); return true; case SYSTEM_CAN_REBOOT: value = CServiceBroker::GetPowerManager().CanReboot(); return true; case SYSTEM_SCREENSAVER_ACTIVE: value = g_application.IsInScreenSaver(); return true; case SYSTEM_DPMS_ACTIVE: value = g_application.IsDPMSActive(); return true; case SYSTEM_HASLOCKS: value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE; return true; case SYSTEM_HAS_PVR: value = true; return true; case SYSTEM_HAS_PVR_ADDON: { ADDON::VECADDONS pvrAddons; ADDON::CBinaryAddonCache &addonCache = CServiceBroker::GetBinaryAddonCache(); addonCache.GetAddons(pvrAddons, ADDON::ADDON_PVRDLL); value = (pvrAddons.size() > 0); return true; } case SYSTEM_HAS_CMS: #if defined(HAS_GL) || defined(HAS_DX) value = true; #else value = false; #endif return true; case SYSTEM_ISMASTER: value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && g_passwordManager.bMasterUser; return true; case SYSTEM_ISFULLSCREEN: value = CServiceBroker::GetWinSystem()->IsFullScreen(); return true; case SYSTEM_ISSTANDALONE: value = g_application.IsStandAlone(); return true; case SYSTEM_ISINHIBIT: value = g_application.IsIdleShutdownInhibited(); return true; case SYSTEM_HAS_SHUTDOWN: value = (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME) > 0); return true; case SYSTEM_LOGGEDON: value = !(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_LOGIN_SCREEN); return true; case SYSTEM_SHOW_EXIT_BUTTON: value = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_showExitButton; return true; case SYSTEM_HAS_LOGINSCREEN: value = CServiceBroker::GetSettingsComponent()->GetProfileManager()->UsingLoginScreen(); return true; case SYSTEM_INTERNET_STATE: { g_sysinfo.GetInfo(info.m_info); value = g_sysinfo.HasInternet(); return true; } case SYSTEM_IDLE_TIME: value = g_application.GlobalIdleTime() >= static_cast<int>(info.GetData1()); return true; case SYSTEM_HAS_CORE_ID: value = g_cpuInfo.HasCoreId(info.GetData1()); return true; case SYSTEM_DATE: { if (info.GetData2() == -1) // info doesn't contain valid startDate return false; const CDateTime date = CDateTime::GetCurrentDateTime(); int currentDate = date.GetMonth() * 100 + date.GetDay(); int startDate = info.GetData1(); int stopDate = info.GetData2(); if (stopDate < startDate) value = currentDate >= startDate || currentDate < stopDate; else value = currentDate >= startDate && currentDate < stopDate; return true; } case SYSTEM_TIME: { int currentTime = CDateTime::GetCurrentDateTime().GetMinuteOfDay(); int startTime = info.GetData1(); int stopTime = info.GetData2(); if (stopTime < startTime) value = currentTime >= startTime || currentTime < stopTime; else value = currentTime >= startTime && currentTime < stopTime; return true; } case SYSTEM_ALARM_LESS_OR_EQUAL: { int time = std::lrint(g_alarmClock.GetRemaining(info.GetData3())); int timeCompare = info.GetData2(); if (time > 0) value = timeCompare >= time; else value = false; return true; } case SYSTEM_HAS_ALARM: value = g_alarmClock.HasAlarm(info.GetData3()); return true; case SYSTEM_GET_BOOL: value = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(info.GetData3()); return true; case SYSTEM_SETTING: { if (StringUtils::EqualsNoCase(info.GetData3(), "hidewatched")) { CGUIMediaWindow* window = GUIINFO::GetMediaWindow(contextWindow); if (window) { value = CMediaSettings::GetInstance().GetWatchedMode(window->CurrentDirectory().GetContent()) == WatchedModeUnwatched; return true; } } break; } } return false; }
void XBPyThread::Process() { CLog::Log(LOGDEBUG,"Python thread: start processing"); int m_Py_file_input = Py_file_input; // get the global lock PyEval_AcquireLock(); PyThreadState* state = Py_NewInterpreter(); if (!state) { PyEval_ReleaseLock(); CLog::Log(LOGERROR,"Python thread: FAILED to get thread state!"); return; } // swap in my thread state PyThreadState_Swap(state); XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook> languageHook(new XBMCAddon::Python::LanguageHook(state->interp)); languageHook->RegisterMe(); m_pExecuter->InitializeInterpreter(addon); CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source); // get path from script file name and add python path's // this is used for python so it will search modules from script path first CStdString scriptDir; URIUtils::GetDirectory(CSpecialProtocol::TranslatePath(m_source), scriptDir); URIUtils::RemoveSlashAtEnd(scriptDir); CStdString path = scriptDir; // add on any addon modules the user has installed ADDON::VECADDONS addons; ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons); for (unsigned int i = 0; i < addons.size(); ++i) #ifdef TARGET_WINDOWS { CStdString strTmp(CSpecialProtocol::TranslatePath(addons[i]->LibPath())); g_charsetConverter.utf8ToSystem(strTmp); path += PY_PATH_SEP + strTmp; } #else path += PY_PATH_SEP + CSpecialProtocol::TranslatePath(addons[i]->LibPath()); #endif // and add on whatever our default path is path += PY_PATH_SEP; // we want to use sys.path so it includes site-packages // if this fails, default to using Py_GetPath PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete if( pathObj && PyList_Check(pathObj) ) { for( int i = 0; i < PyList_Size(pathObj); i++ ) { PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete if( e && PyString_Check(e) ) { path += PyString_AsString(e); // returns internal data, don't delete or modify path += PY_PATH_SEP; } } } else { path += Py_GetPath(); } Py_DECREF(sysMod); // release ref to sysMod // set current directory and python's path. if (m_argv != NULL) PySys_SetArgv(m_argc, m_argv); CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path.c_str()); PySys_SetPath((char *)path.c_str()); CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, scriptDir.c_str()); PyObject* module = PyImport_AddModule((char*)"__main__"); PyObject* moduleDict = PyModule_GetDict(module); // when we are done initing we store thread state so we can be aborted PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // we need to check if we was asked to abort before we had inited bool stopping = false; { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = state; stopping = m_stopping; } PyEval_AcquireLock(); PyThreadState_Swap(state); if (!stopping) { try { if (m_type == 'F') { // run script from file // We need to have python open the file because on Windows the DLL that python // is linked against may not be the DLL that xbmc is linked against so // passing a FILE* to python from an fopen has the potential to crash. PyObject* file = PyFile_FromString((char *) CSpecialProtocol::TranslatePath(m_source).c_str(), (char*)"r"); FILE *fp = PyFile_AsFile(file); if (fp) { PyObject *f = PyString_FromString(CSpecialProtocol::TranslatePath(m_source).c_str()); PyDict_SetItemString(moduleDict, "__file__", f); if (addon.get() != NULL) { PyObject *pyaddonid = PyString_FromString(addon->ID().c_str()); PyDict_SetItemString(moduleDict, "__xbmcaddonid__", pyaddonid); CStdString version = ADDON::GetXbmcApiVersionDependency(addon); PyObject *pyxbmcapiversion = PyString_FromString(version.c_str()); PyDict_SetItemString(moduleDict, "__xbmcapiversion__", pyxbmcapiversion); CLog::Log(LOGDEBUG,"Instantiating addon using automatically obtained id of \"%s\" dependent on version %s of the xbmc.python api",addon->ID().c_str(),version.c_str()); } Py_DECREF(f); XBMCAddon::Python::PyContext pycontext; // this is a guard class that marks this callstack as being in a python context PyRun_FileExFlags(fp, CSpecialProtocol::TranslatePath(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict,1,NULL); } else CLog::Log(LOGERROR, "%s not found!", m_source); } else { //run script PyRun_String(m_source, m_Py_file_input, moduleDict, moduleDict); } } catch (const XbmcCommons::Exception& e) { e.LogThrowMessage(); } catch (...) { CLog::Log(LOGERROR, "failure in %s", m_source); } } if (!PyErr_Occurred()) CLog::Log(LOGINFO, "Scriptresult: Success"); else if (PyErr_ExceptionMatches(PyExc_SystemExit)) CLog::Log(LOGINFO, "Scriptresult: Aborted"); else { PythonBindings::PythonToCppException e; e.LogThrowMessage(); { CPyThreadState releaseGil; CSingleLock gc(g_graphicsContext); CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST); if (pDlgToast) { CStdString desc; CStdString path; CStdString script; URIUtils::Split(m_source, path, script); if (script.Equals("default.py")) { CStdString path2; URIUtils::RemoveSlashAtEnd(path); URIUtils::Split(path, path2, script); } desc.Format(g_localizeStrings.Get(2100), script); pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc); } } } PyObject *m = PyImport_AddModule((char*)"xbmc"); if(!m || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1))) CLog::Log(LOGERROR, "Scriptresult: failed to set abortRequested"); // make sure all sub threads have finished for(PyThreadState* s = state->interp->tstate_head, *old = NULL; s;) { if(s == state) { s = s->next; continue; } if(old != s) { CLog::Log(LOGINFO, "Scriptresult: Waiting on thread %"PRIu64, (uint64_t)s->thread_id); old = s; } CPyThreadState pyState; Sleep(100); pyState.Restore(); s = state->interp->tstate_head; } // pending calls must be cleared out XBMCAddon::RetardedAsynchCallbackHandler::clearPendingCalls(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); //set stopped event - this allows ::stop to run and kill remaining threads //this event has to be fired without holding m_pExecuter->m_critSection //before //Also the GIL (PyEval_AcquireLock) must not be held //if not obeyed there is still no deadlock because ::stop waits with timeout (smart one!) stoppedEvent.Set(); { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = NULL; } PyEval_AcquireLock(); PyThreadState_Swap(state); m_pExecuter->DeInitializeInterpreter(); // run the gc before finishing if (!m_stopping && languageHook->HasRegisteredAddonClasses() && PyRun_SimpleString(GC_SCRIPT) == -1) CLog::Log(LOGERROR,"Failed to run the gc to clean up after running prior to shutting down the Interpreter %s",m_source); Py_EndInterpreter(state); // This is a total hack. Python doesn't necessarily release // all of the objects associated with the interpreter when // you end the interpreter. As a result there are objects // managed by the windowing system that still receive events // until python decides to clean them up. Python will eventually // clean them up on the creation or ending of a subsequent // interpreter. So we are going to keep creating and ending // interpreters until we have no more python objects hanging // around. if (languageHook->HasRegisteredAddonClasses()) { CLog::Log(LOGDEBUG, "The python script \"%s\" has left several " "classes in memory that we will be attempting to clean up. The classes include: %s", m_source, getListOfAddonClassesAsString(languageHook).c_str()); int countLimit; for (countLimit = 0; languageHook->HasRegisteredAddonClasses() && countLimit < 100; countLimit++) { PyThreadState* tmpstate = Py_NewInterpreter(); PyThreadState* oldstate = PyThreadState_Swap(tmpstate); if (PyRun_SimpleString(GC_SCRIPT) == -1) CLog::Log(LOGERROR,"Failed to run the gc to clean up after running %s",m_source); PyThreadState_Swap(oldstate); Py_EndInterpreter(tmpstate); } // If necessary and successfull, debug log the results. if (countLimit > 0 && !languageHook->HasRegisteredAddonClasses()) CLog::Log(LOGDEBUG,"It took %d Py_NewInterpreter/Py_EndInterpreter calls" " to clean up the classes leftover from running \"%s.\"", countLimit,m_source); // If not successful, produce an error message detailing what's been left behind if (languageHook->HasRegisteredAddonClasses()) CLog::Log(LOGERROR, "The python script \"%s\" has left several " "classes in memory that we couldn't clean up. The classes include: %s", m_source, getListOfAddonClassesAsString(languageHook).c_str()); } // unregister the language hook languageHook->UnregisterMe(); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); }
bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */) { bool bReturn(true); ADDON::VECADDONS map; ADDON::VECADDONS disableAddons; { CSingleLock lock(m_critSection); map = m_addons; } if (map.size() == 0) return false; for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++) { const AddonPtr clientAddon = map.at(iClientPtr); bool bEnabled = clientAddon->Enabled() && !m_addonDb.IsAddonDisabled(clientAddon->ID()); if (!bEnabled && IsKnownClient(clientAddon)) { CSingleLock lock(m_critSection); /* stop the client and remove it from the db */ StopClient(clientAddon, false); ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), clientAddon); if (addonPtr != m_addons.end()) m_addons.erase(addonPtr); } else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(clientAddon) || !IsConnectedClient(clientAddon))) { bool bDisabled(false); // register the add-on in the pvr db, and create the CPVRClient instance int iClientId = RegisterClient(clientAddon); if (iClientId < 0) { // failed to register or create the add-on, disable it CLog::Log(LOGWARNING, "%s - failed to register add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } else { PVR_CLIENT addon; if (!GetClient(iClientId, addon)) { CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } // re-check the enabled status. newly installed clients get disabled when they're added to the db else if (addon->Enabled() && !addon->Create(iClientId)) { CLog::Log(LOGWARNING, "%s - failed to create add-on %s", __FUNCTION__, clientAddon->Name().c_str()); if (!addon.get() || !addon->DllLoaded()) { // failed to load the dll of this add-on, disable it CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str()); disableAddons.push_back(clientAddon); bDisabled = true; } } } if (bDisabled && (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting)) CGUIDialogOK::ShowAndGetInput(24070, 24071, 16029, 0); } } // disable add-ons that failed to initialise if (disableAddons.size() > 0) { CSingleLock lock(m_critSection); for (ADDON::VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); it++) { // disable in the add-on db m_addonDb.DisableAddon((*it)->ID(), true); // remove from the pvr add-on list ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), *it); if (addonPtr != m_addons.end()) m_addons.erase(addonPtr); } } return bReturn; }
bool CPythonInvoker::execute(const std::string &script, const std::vector<std::string> &arguments) { // copy the code/script into a local string buffer #ifdef TARGET_WINDOWS CStdString strsrc = script; g_charsetConverter.utf8ToSystem(strsrc); m_source = new char[strsrc.length() + 1]; strcpy(m_source, strsrc); #else m_source = new char[script.length() + 1]; strcpy(m_source, script.c_str()); #endif // copy the arguments into a local buffer m_argc = arguments.size(); m_argv = new char*[m_argc]; for (unsigned int i = 0; i < m_argc; i++) { m_argv[i] = new char[arguments.at(i).length() + 1]; strcpy(m_argv[i], arguments.at(i).c_str()); } CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): start processing", GetId(), m_source); int m_Py_file_input = Py_file_input; // get the global lock PyEval_AcquireLock(); PyThreadState* state = Py_NewInterpreter(); if (state == NULL) { PyEval_ReleaseLock(); CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): FAILED to get thread state!", GetId(), m_source); return false; } // swap in my thread state PyThreadState_Swap(state); XBMCAddon::AddonClass::Ref<XBMCAddon::Python::LanguageHook> languageHook(new XBMCAddon::Python::LanguageHook(state->interp)); languageHook->RegisterMe(); g_pythonParser.InitializeInterpreter(m_addon); setState(InvokerStateInitialized); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): the source file to load is %s", GetId(), m_source, m_source); // get path from script file name and add python path's // this is used for python so it will search modules from script path first CStdString scriptDir; URIUtils::GetDirectory(CSpecialProtocol::TranslatePath(m_source), scriptDir); URIUtils::RemoveSlashAtEnd(scriptDir); addPath(scriptDir); // add on any addon modules the user has installed ADDON::VECADDONS addons; ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons); for (unsigned int i = 0; i < addons.size(); ++i) addPath(CSpecialProtocol::TranslatePath(addons[i]->LibPath())); // we want to use sys.path so it includes site-packages // if this fails, default to using Py_GetPath PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete if (pathObj != NULL && PyList_Check(pathObj)) { for (int i = 0; i < PyList_Size(pathObj); i++) { PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete if (e != NULL && PyString_Check(e)) addPath(PyString_AsString(e)); // returns internal data, don't delete or modify } } else addPath(Py_GetPath()); Py_DECREF(sysMod); // release ref to sysMod // set current directory and python's path. if (m_argv != NULL) PySys_SetArgv(m_argc, m_argv); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): setting the Python path to %s", GetId(), m_source, m_pythonPath.c_str()); PySys_SetPath((char *)m_pythonPath.c_str()); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): entering source directory %s", GetId(), m_source, scriptDir.c_str()); PyObject* module = PyImport_AddModule((char*)"__main__"); PyObject* moduleDict = PyModule_GetDict(module); // when we are done initing we store thread state so we can be aborted PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // we need to check if we was asked to abort before we had inited bool stopping = false; { CSingleLock lock(m_critical); m_threadState = state; stopping = m_stop; } PyEval_AcquireLock(); PyThreadState_Swap(state); bool failed = false; if (!stopping) { try { // run script from file // We need to have python open the file because on Windows the DLL that python // is linked against may not be the DLL that xbmc is linked against so // passing a FILE* to python from an fopen has the potential to crash. PyObject* file = PyFile_FromString((char *) CSpecialProtocol::TranslatePath(m_source).c_str(), (char*)"r"); FILE *fp = PyFile_AsFile(file); if (fp != NULL) { PyObject *f = PyString_FromString(CSpecialProtocol::TranslatePath(m_source).c_str()); PyDict_SetItemString(moduleDict, "__file__", f); if (m_addon.get() != NULL) { PyObject *pyaddonid = PyString_FromString(m_addon->ID().c_str()); PyDict_SetItemString(moduleDict, "__xbmcaddonid__", pyaddonid); CStdString version = ADDON::GetXbmcApiVersionDependency(m_addon); PyObject *pyxbmcapiversion = PyString_FromString(version.c_str()); PyDict_SetItemString(moduleDict, "__xbmcapiversion__", pyxbmcapiversion); CLog::Log(LOGDEBUG, "CPythonInvoker(%d, %s): instantiating addon using automatically obtained id of \"%s\" dependent on version %s of the xbmc.python api", GetId(), m_source, m_addon->ID().c_str(), version.c_str()); } Py_DECREF(f); setState(InvokerStateRunning); XBMCAddon::Python::PyContext pycontext; // this is a guard class that marks this callstack as being in a python context PyRun_FileExFlags(fp, CSpecialProtocol::TranslatePath(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict,1,NULL); } else CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): %s not found!", GetId(), m_source, m_source); } catch (const XbmcCommons::Exception& e) { setState(InvokerStateFailed); e.LogThrowMessage(); failed = true; } catch (...) { setState(InvokerStateFailed); CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failure in script", GetId(), m_source); failed = true; } } bool systemExitThrown = false; if (!failed && !PyErr_Occurred()) { CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script successfully run", GetId(), m_source); setState(InvokerStateDone); } else if (PyErr_ExceptionMatches(PyExc_SystemExit)) { systemExitThrown = true; CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): script aborted", GetId(), m_source); setState(InvokerStateFailed); } else { setState(InvokerStateFailed); // if it failed with an exception we already logged the details if (!failed) { PythonBindings::PythonToCppException e; e.LogThrowMessage(); } { CPyThreadState releaseGil; CSingleLock gc(g_graphicsContext); CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST); if (pDlgToast != NULL) { CStdString desc; CStdString script; if (m_addon.get() != NULL) script = m_addon->Name(); else { CStdString path; URIUtils::Split(m_source, path, script); if (script.Equals("default.py")) { CStdString path2; URIUtils::RemoveSlashAtEnd(path); URIUtils::Split(path, path2, script); } } desc.Format(g_localizeStrings.Get(2100), script); pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc); } } } // no need to do anything else because the script has already stopped if (failed) return true; PyObject *m = PyImport_AddModule((char*)"xbmc"); if (m == NULL || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1))) CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to set abortRequested", GetId(), m_source); // make sure all sub threads have finished for (PyThreadState* s = state->interp->tstate_head, *old = NULL; s;) { if (s == state) { s = s->next; continue; } if (old != s) { CLog::Log(LOGINFO, "CPythonInvoker(%d, %s): waiting on thread %"PRIu64, GetId(), m_source, (uint64_t)s->thread_id); old = s; } CPyThreadState pyState; Sleep(100); pyState.Restore(); s = state->interp->tstate_head; } // pending calls must be cleared out XBMCAddon::RetardedAsynchCallbackHandler::clearPendingCalls(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // set stopped event - this allows ::stop to run and kill remaining threads // this event has to be fired without holding m_critical // also the GIL (PyEval_AcquireLock) must not be held // if not obeyed there is still no deadlock because ::stop waits with timeout (smart one!) m_stoppedEvent.Set(); { CSingleLock lock(m_critical); m_threadState = NULL; } PyEval_AcquireLock(); PyThreadState_Swap(state); g_pythonParser.DeInitializeInterpreter(); // run the gc before finishing // // if the script exited by throwing a SystemExit excepton then going back // into the interpreter causes this python bug to get hit: // http://bugs.python.org/issue10582 // and that causes major failures. So we are not going to go back in // to run the GC if that's the case. if (!m_stop && languageHook->HasRegisteredAddonClasses() && !systemExitThrown && PyRun_SimpleString(GC_SCRIPT) == -1) CLog::Log(LOGERROR, "CPythonInvoker(%d, %s): failed to run the gc to clean up after running prior to shutting down the Interpreter", GetId(), m_source); Py_EndInterpreter(state); // If we still have objects left around, produce an error message detailing what's been left behind if (languageHook->HasRegisteredAddonClasses()) CLog::Log(LOGWARNING, "CPythonInvoker(%d, %s): the python script \"%s\" has left several " "classes in memory that we couldn't clean up. The classes include: %s", GetId(), m_source, m_source, getListOfAddonClassesAsString(languageHook).c_str()); // unregister the language hook languageHook->UnregisterMe(); PyEval_ReleaseLock(); return true; }
void XBPyThread::Process() { CLog::Log(LOGDEBUG,"Python thread: start processing"); int m_Py_file_input = Py_file_input; // get the global lock PyEval_AcquireLock(); PyThreadState* state = Py_NewInterpreter(); if (!state) { PyEval_ReleaseLock(); CLog::Log(LOGERROR,"Python thread: FAILED to get thread state!"); return; } // swap in my thread state PyThreadState_Swap(state); m_pExecuter->InitializeInterpreter(); CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source); // get path from script file name and add python path's // this is used for python so it will search modules from script path first CStdString scriptDir; URIUtils::GetDirectory(_P(m_source), scriptDir); URIUtils::RemoveSlashAtEnd(scriptDir); CStdString path = scriptDir; // add on any addon modules the user has installed ADDON::VECADDONS addons; ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons); for (unsigned int i = 0; i < addons.size(); ++i) path += PY_PATH_SEP + _P(addons[i]->LibPath()); // and add on whatever our default path is path += PY_PATH_SEP; { // we want to use sys.path so it includes site-packages // if this fails, default to using Py_GetPath PyObject *sysMod(PyImport_ImportModule((char*)"sys")); // must call Py_DECREF when finished PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete if( pathObj && PyList_Check(pathObj) ) { for( int i = 0; i < PyList_Size(pathObj); i++ ) { PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete if( e && PyString_Check(e) ) { path += PyString_AsString(e); // returns internal data, don't delete or modify path += PY_PATH_SEP; } } } else { path += Py_GetPath(); } Py_DECREF(sysMod); // release ref to sysMod } // set current directory and python's path. if (m_argv != NULL) PySys_SetArgv(m_argc, m_argv); CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path.c_str()); PySys_SetPath((char *)path.c_str()); CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, scriptDir.c_str()); PyObject* module = PyImport_AddModule((char*)"__main__"); PyObject* moduleDict = PyModule_GetDict(module); // when we are done initing we store thread state so we can be aborted PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // we need to check if we was asked to abort before we had inited bool stopping = false; { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = state; stopping = m_stopping; } PyEval_AcquireLock(); PyThreadState_Swap(state); if (!stopping) { if (m_type == 'F') { // run script from file // We need to have python open the file because on Windows the DLL that python // is linked against may not be the DLL that xbmc is linked against so // passing a FILE* to python from an fopen has the potential to crash. PyObject* file = PyFile_FromString((char *) _P(m_source).c_str(), (char*)"r"); FILE *fp = PyFile_AsFile(file); if (fp) { PyObject *f = PyString_FromString(_P(m_source).c_str()); PyDict_SetItemString(moduleDict, "__file__", f); Py_DECREF(f); PyRun_File(fp, _P(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict); // Get a reference to the main module // and global dictionary PyObject* main_module = PyImport_AddModule((char*)"__main__"); PyObject* global_dict = PyModule_GetDict(main_module); // Extract a reference to the function "func_name" // from the global dictionary PyObject* expression = PyDict_GetItemString(global_dict, "xbmcclosefilehack"); if (!PyObject_CallFunction(expression,(char*)"(O)",file)) CLog::Log(LOGERROR,"Failed to close the script file %s",_P(m_source).c_str()); } else CLog::Log(LOGERROR, "%s not found!", m_source); } else { //run script PyRun_String(m_source, m_Py_file_input, moduleDict, moduleDict); } } if (!PyErr_Occurred()) CLog::Log(LOGINFO, "Scriptresult: Success"); else if (PyErr_ExceptionMatches(PyExc_SystemExit)) CLog::Log(LOGINFO, "Scriptresult: Aborted"); else { PyObject* exc_type; PyObject* exc_value; PyObject* exc_traceback; PyObject* pystring; pystring = NULL; PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); if (exc_type == 0 && exc_value == 0 && exc_traceback == 0) { CLog::Log(LOGINFO, "Strange: No Python exception occured"); } else { if (exc_type != NULL && (pystring = PyObject_Str(exc_type)) != NULL && (PyString_Check(pystring))) { PyObject *tracebackModule; CLog::Log(LOGINFO, "-->Python script returned the following error<--"); CLog::Log(LOGERROR, "Error Type: %s", PyString_AsString(PyObject_Str(exc_type))); if (PyObject_Str(exc_value)) CLog::Log(LOGERROR, "Error Contents: %s", PyString_AsString(PyObject_Str(exc_value))); tracebackModule = PyImport_ImportModule((char*)"traceback"); if (tracebackModule != NULL) { PyObject *tbList, *emptyString, *strRetval; tbList = PyObject_CallMethod(tracebackModule, (char*)"format_exception", (char*)"OOO", exc_type, exc_value == NULL ? Py_None : exc_value, exc_traceback == NULL ? Py_None : exc_traceback); emptyString = PyString_FromString(""); strRetval = PyObject_CallMethod(emptyString, (char*)"join", (char*)"O", tbList); CLog::Log(LOGERROR, "%s", PyString_AsString(strRetval)); Py_DECREF(tbList); Py_DECREF(emptyString); Py_DECREF(strRetval); Py_DECREF(tracebackModule); } CLog::Log(LOGINFO, "-->End of Python script error report<--"); } else { pystring = NULL; CLog::Log(LOGINFO, "<unknown exception type>"); } CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST); if (pDlgToast) { CStdString desc; CStdString path; CStdString script; URIUtils::Split(m_source, path, script); if (script.Equals("default.py")) { CStdString path2; URIUtils::RemoveSlashAtEnd(path); URIUtils::Split(path, path2, script); } desc.Format(g_localizeStrings.Get(2100), script); pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc); } } Py_XDECREF(exc_type); Py_XDECREF(exc_value); // caller owns all 3 Py_XDECREF(exc_traceback); // already NULL'd out Py_XDECREF(pystring); } PyObject *m = PyImport_AddModule((char*)"xbmc"); if(!m || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1))) CLog::Log(LOGERROR, "Scriptresult: failed to set abortRequested"); // make sure all sub threads have finished for(PyThreadState* s = state->interp->tstate_head, *old = NULL; s;) { if(s == state) { s = s->next; continue; } if(old != s) { CLog::Log(LOGINFO, "Scriptresult: Waiting on thread %"PRIu64, (uint64_t)s->thread_id); old = s; } CPyThreadState pyState; Sleep(100); pyState.Restore(); s = state->interp->tstate_head; } // pending calls must be cleared out PyXBMC_ClearPendingCalls(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = NULL; } PyEval_AcquireLock(); PyThreadState_Swap(state); m_pExecuter->DeInitializeInterpreter(); Py_EndInterpreter(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); }
CDVDInputStream* CDVDFactoryInputStream::CreateInputStream(IVideoPlayer* pPlayer, CFileItem fileitem) { std::string file = fileitem.GetPath(); ADDON::VECADDONS addons; ADDON::CAddonMgr::GetInstance().GetAddons(addons, ADDON::ADDON_INPUTSTREAM); for (size_t i=0; i<addons.size(); ++i) { std::shared_ptr<ADDON::CInputStream> input(std::static_pointer_cast<ADDON::CInputStream>(addons[i])); ADDON::CInputStream* clone = new ADDON::CInputStream(*input); ADDON_STATUS status = clone->Supports(fileitem) ? clone->Create() : ADDON_STATUS_PERMANENT_FAILURE; if (status == ADDON_STATUS_OK) { if (clone->Supports(fileitem)) { return new CInputStreamAddon(fileitem, clone); } } delete clone; } if (fileitem.IsDiscImage()) { #ifdef HAVE_LIBBLURAY CURL url("udf://"); url.SetHostName(file); url.SetFileName("BDMV/index.bdmv"); if(XFILE::CFile::Exists(url.Get())) return new CDVDInputStreamBluray(pPlayer, fileitem); #endif return new CDVDInputStreamNavigator(pPlayer, fileitem); } #ifdef HAS_DVD_DRIVE if(file.compare(g_mediaManager.TranslateDevicePath("")) == 0) { #ifdef HAVE_LIBBLURAY if(XFILE::CFile::Exists(URIUtils::AddFileToFolder(file, "BDMV/index.bdmv"))) return new CDVDInputStreamBluray(pPlayer, fileitem); #endif return new CDVDInputStreamNavigator(pPlayer, fileitem); } #endif if (fileitem.IsDVDFile(false, true)) return (new CDVDInputStreamNavigator(pPlayer, fileitem)); else if(file.substr(0, 6) == "pvr://") return new CDVDInputStreamPVRManager(pPlayer, fileitem); #ifdef HAVE_LIBBLURAY else if (fileitem.IsType(".bdmv") || fileitem.IsType(".mpls") || file.substr(0, 7) == "bluray:") return new CDVDInputStreamBluray(pPlayer, fileitem); #endif else if(file.substr(0, 6) == "rtp://" || file.substr(0, 7) == "rtsp://" || file.substr(0, 6) == "sdp://" || file.substr(0, 6) == "udp://" || file.substr(0, 6) == "tcp://" || file.substr(0, 6) == "mms://" || file.substr(0, 7) == "mmst://" || file.substr(0, 7) == "mmsh://") return new CDVDInputStreamFFmpeg(fileitem); #ifdef ENABLE_DVDINPUTSTREAM_STACK else if(file.substr(0, 8) == "stack://") return new CDVDInputStreamStack(fileitem); #endif #ifdef HAS_LIBRTMP else if(file.substr(0, 7) == "rtmp://" || file.substr(0, 8) == "rtmpt://" || file.substr(0, 8) == "rtmpe://" || file.substr(0, 9) == "rtmpte://" || file.substr(0, 8) == "rtmps://") return new CDVDInputStreamRTMP(fileitem); #endif else if (fileitem.IsInternetStream()) { if (fileitem.IsType(".m3u8")) return new CDVDInputStreamFFmpeg(fileitem); if (fileitem.ContentLookup()) { // request header fileitem.SetMimeType(""); fileitem.FillInMimeType(); } if (fileitem.GetMimeType() == "application/vnd.apple.mpegurl") return new CDVDInputStreamFFmpeg(fileitem); } // our file interface handles all these types of streams return (new CDVDInputStreamFile(fileitem)); }