void PersistCommand::Validate(bool checkTokenValid) const { LOG_AM_TRACE("Entering function %s", __FUNCTION__); if (!m_activity->IsPersistTokenSet()) { LOG_AM_ERROR(MSGID_PERSIST_TOKEN_NOT_SET,2, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()), "Persist token for Activity is not set"); throw std::runtime_error("Persist token for Activity is not set"); } if (checkTokenValid) { boost::shared_ptr<PersistToken> pt = m_activity->GetPersistToken(); if (!pt->IsValid()) { LOG_AM_ERROR(MSGID_PERSIST_TOKEN_INVALID, 2, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()), "Persist token for Activity is set but not valid" ); throw std::runtime_error("Persist token for Activity is set " "but not valid"); } } }
boost::shared_ptr<Requirement> PowerdProxy::InstantiateRequirement( boost::shared_ptr<Activity> activity, const std::string& name, const MojObject& value) { LOG_TRACE("Entering function %s", __FUNCTION__); LOG_DEBUG("Instantiating [Requirement %s] for [Activity %llu]", name.c_str(), activity->GetId()); if (name == "charging") { if ((value.type() != MojObject::TypeBool) || !value.boolValue()) { throw std::runtime_error("A \"charging\" requirement must specify " "'true' if present"); } boost::shared_ptr<ListedRequirement> req = boost::make_shared<BasicCoreListedRequirement>( activity, m_chargingRequirementCore, m_chargingRequirementCore->IsMet()); m_chargingRequirements.push_back(*req); return req; } else if (name == "docked") { if ((value.type() != MojObject::TypeBool) || !value.boolValue()) { throw std::runtime_error("A \"docked\" requirement must specify " "'true' if present"); } boost::shared_ptr<ListedRequirement> req = boost::make_shared<BasicCoreListedRequirement>( activity, m_dockedRequirementCore, m_dockedRequirementCore->IsMet()); m_dockedRequirements.push_back(*req); return req; } else if (name == "battery") { if ((value.type() != MojObject::TypeInt) || (value.intValue() < 0) || (value.intValue() > 100)) { throw std::runtime_error("A \"battery\" requirement must specify " "a value between 0 and 100"); } MojInt64 percent = value.intValue(); boost::shared_ptr<BatteryRequirement> req = boost::make_shared<BatteryRequirement>(activity, percent, boost::dynamic_pointer_cast<PowerdProxy, RequirementManager>(shared_from_this()), (m_batteryPercent >= percent)); m_batteryRequirements.insert(*req); return req; } else { LOG_ERROR(MSGID_UNKNOW_REQUIREMENT,3, PMLOGKS("MANAGER",GetName().c_str()), PMLOGKS("REQUIREMENT",name.c_str()), PMLOGKFV("Activity","%llu",activity->GetId()), "does not know how to instantiate "); throw std::runtime_error("Attempt to instantiate unknown requirement"); } }
MojErr MojDbLevelIndex::del(const MojDbKey& key, MojDbStorageTxn* txn) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(txn); MojAssert(isOpen()); MojDbLevelItem keyItem; keyItem.fromBytesNoCopy(key.data(), key.size()); bool found = false; MojErr err = m_db->del(keyItem, found, txn); #ifdef MOJ_DEBUG char s[1024]; size_t size1 = keyItem.size(); MojErr err2 = MojByteArrayToHex(keyItem.data(), size1, s); MojErrCheck(err2); if (size1 > 16) // if the object-id is in key strncat(s, (char *)(keyItem.data()) + (size1 - 17), 16); LOG_DEBUG("[db_ldb] ldbindexdel: %s; keylen: %zu, key: %s ; err = %d\n", m_db->m_name.data(), size1, s, err); if (!found) LOG_WARNING(MSGID_LEVEL_DB_WARNING, 1, PMLOGKS("index", s), "ldbindexdel_warn: not found: %s \n", s); #endif MojErrCheck(err); if (!found) { //MojErrThrow(MojErrDbInconsistentIndex); // fix this to work around to deal with out of sync indexes MojErrThrow(MojErrInternalIndexOnDel); } return MojErrNone; }
void sysServiceLogInfo(const char * fileName, guint32 lineNbr,const char* funcName, const char *logMsg) { PmLogContext pmContext = sysServiceLogContext(); // Length will be an arbitrary short string with length up to 31 char msgId[MSGID_LENGTH+1]; PmLogInfo(pmContext, fmtUniqueLogId(msgId, fileName, lineNbr), 1, PMLOGKS("FUNC", funcName), "%s", logMsg); }
void Subscription::HandleCancelWrapper() { LOG_TRACE("Entering function %s", __FUNCTION__); LOG_DEBUG("%s cancelling subscription", GetSubscriber().GetString().c_str()); try { m_activity->RemoveSubscription(shared_from_this()); /* Any specialized implementation for the specific Subscription type */ HandleCancel(); } catch (const std::exception& except) { LOG_ERROR(MSGID_SUBSCRIPTION_CANCEL_FAIL, 1, PMLOGKS("SUBSCRIBER",GetSubscriber().GetString().c_str() ), "Unhandled exception \"%s\" occurred while cancelling subscription", except.what()); } catch (...) { LOG_ERROR(MSGID_SUBSCRIPTION_CANCEL_ERR,1, PMLOGKS("SUBSCRIBER",GetSubscriber().GetString().c_str() ), "Unhandled exception of unknown type occurred cancelling subscription"); } }
MojErr MojDbLunaServiceDb::recoverDb(MojDbEnv* env, const MojChar* dir, const MojObject& conf) { MojErr err; if (m_recoveryScriptPath.empty()) { LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN,0, "No recovery script, close database"); return MojErrDbFatal; } int recoveryResult = system(m_recoveryScriptPath.data()); if (recoveryResult != 0) { LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN, 3, PMLOGKS("recoveryScript", m_recoveryScriptPath.data()), PMLOGKFV("scriptExecResult", "%i", recoveryResult), PMLOGKS("dbdir", dir), "Can't recovery database with help of recovery script"); return MojErrDbFatal; // close database and stop process } LOG_INFO(MSGID_LUNA_SERVICE_DB_OPEN, 0, "Recovery database success, reopen database" ); err = openDb(env, dir, conf); if (err != MojErrNone) { MojString msg; MojErrToString(err, msg); LOG_ERROR(MSGID_LUNA_SERVICE_DB_OPEN, 3, PMLOGKS("dbdir", dir), PMLOGKS("dbdata", msg.data()), PMLOGKFV("dberror", "%d", err), "Error re-opening database after recovery"); return err; } return MojErrNone; }
/* Append the new command to the end of the command chain that this * command is a member of. */ void PersistCommand::Append(boost::shared_ptr<PersistCommand> command) { LOG_AM_TRACE("Entering function %s", __FUNCTION__); if (command == shared_from_this()) { LOG_AM_WARNING(MSGID_APPEND_CMD_TOSELF,1,PMLOGKS("persist_command",GetString().c_str()), "Attempt to append command directly to itself"); throw std::runtime_error("Attempt to append Persist Command directly " "to itself"); } boost::shared_ptr<PersistCommand> target; for (target = shared_from_this(); target->m_next; target = target->m_next) { if (target->m_next == shared_from_this()) { LOG_AM_WARNING( MSGID_APPEND_CREATE_LOOP, 2, PMLOGKS("persist_command",command->GetString().c_str()), PMLOGKS("persist_command",target->GetString().c_str()),"Append Failed"); throw std::runtime_error("Attempt to append Persist Command would " "create a loop"); } } target->m_next = command; }
MojErr MojDbLunaServiceDb::open(MojGmainReactor& reactor, MojDbEnv* env, const MojChar* serviceName, const MojChar* dir, const MojObject& conf) { LOG_TRACE("Entering function %s", __FUNCTION__); // open service MojErr err = m_service.open(serviceName); MojErrCheck(err); err = m_service.attach(reactor.impl()); MojErrCheck(err); // open handler err = m_handler->open(); MojErrCheck(err); err = m_service.addCategory(MojDbServiceDefs::Category, m_handler.get()); MojErrCheck(err); LOG_DEBUG("[MojDb] service name: %s", serviceName); // open db err = openDb(env, dir, conf); if (err != MojErrNone) { MojString msg; MojErrToString(err, msg); LOG_WARNING(MSGID_LUNA_SERVICE_DB_OPEN, 3, PMLOGKS("dbdir", dir), PMLOGKS("dbdata", msg.data()), PMLOGKFV("dberror", "%d", err), "Can't open database"); err = recoverDb(env, dir, conf); MojErrCheck(err); } return err; }
MojErr MojDbIndex::addWatch(const MojDbQueryPlan& plan, MojDbCursor& cursor, MojDbWatcher* watcher, MojDbReq& req) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(watcher); // TODO: use interval tree instead of vector for watches MojThreadWriteGuard guard(m_lock); MojErr err = m_watcherVec.push(watcher); MojErrCheck(err); // update count map watcher->domain(req.domain()); WatcherMap::Iterator iter; err = m_watcherMap.find(req.domain(), iter); MojErrCheck(err); if (iter == m_watcherMap.end()) { err = m_watcherMap.put(req.domain(), 1); MojErrCheck(err); } else { iter.value() += 1; if (iter.value() > WatchWarningThreshold) { LOG_WARNING(MSGID_MOJ_DB_INDEX_WARNING, 4, PMLOGKS("domain", req.domain().data()), PMLOGKFV("iter", "%zd", iter.value()), PMLOGKS("kindId", m_kind->id().data()), PMLOGKS("name", m_name.data()), "db:'domain' has 'iter' watches open on index 'kindId - name'"); } } LOG_DEBUG("[db_mojodb] DbIndex_addWatch - '%s' on index '%s - %s'", req.domain().data(), m_kind->id().data(), m_name.data()); // drop lock before acquiring watcher mutex in init guard.unlock(); watcher->init(this, plan.ranges(), plan.desc(), false); return MojErrNone; }
MojErr MojDbLunaServiceDb::configure(const MojObject& conf) { MojErr err; err = conf.getRequired("recoveryScriptPath", m_recoveryScriptPath); MojErrCheck(err); // check if bash scipt exist and have exec rights if (access(m_recoveryScriptPath.data(), X_OK) != 0) { LOG_WARNING(MSGID_LUNA_SERVICE_DB_OPEN, 1, PMLOGKS("recoveryScriptPath", m_recoveryScriptPath.data()), "Can't find recovery script or no exec right"); m_recoveryScriptPath.clear(); } return MojErrNone; }
void PersistCommand::Complete(bool success) { LOG_AM_TRACE("Entering function %s", __FUNCTION__); /* All steps of Complete must execute, including launching the next * command in the chain. All exceptions must be handled locally. */ try { m_completion->Complete(success); } catch (const std::exception& except) { LOG_AM_WARNING(MSGID_CMD_COMPLETE_EXCEPTION,3, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()), PMLOGKS("exception",except.what()),"Unexpected exception while trying to complete"); } catch (...) { LOG_AM_WARNING(MSGID_CMD_COMPLETE_EXCEPTION,2, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()),"exception while trying to complete"); } /* Tricky order here. Unhooking this command will probably destroy it, * so we have to pick up a local reference to the next command in the * chain because we won't be able to access the object property. * * The whole chain shouldn't collapse, though, as the next executing * command should be referenced by the same Activity or some other one. * It's just the reference that's bad... but since something like: * Complete "foo"/Create(and replace) "foo"/Cancel old "foo". If the * Complete is still in process, the Cancel will chain (and ultimately * will succeed as the Activity is already cancelled). */ boost::shared_ptr<PersistCommand> next = m_next; try { m_activity->UnhookPersistCommand(shared_from_this()); } catch (const std::exception& except) { LOG_AM_WARNING( MSGID_CMD_UNHOOK_EXCEPTION,3, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()), PMLOGKS("exception",except.what()),"Unexpected exception unhooking command" ); } catch (...) { LOG_AM_WARNING(MSGID_CMD_UNHOOK_EXCEPTION,2, PMLOGKFV("activity","%llu",m_activity->GetId()), PMLOGKS("persist_command",GetString().c_str()),"exception unhooking command"); } if (next) { next->Persist(); } }
ConversionResultFlags jstr_to_double(raw_buffer *str, double *result) { ConversionResultFlags conv_result; int64_t wholeComponent = 0; int64_t fraction = 0; int64_t fractionLeadingZeros = 0; int64_t exponent = 0; CHECK_POINTER_RETURN_VALUE(result, CONV_BAD_ARGS); conv_result = parseJSONNumber(str, &wholeComponent, &exponent, &fraction, &fractionLeadingZeros); if (UNLIKELY(CONV_IS_BAD_ARGS(conv_result) || CONV_IS_GENERIC_ERROR(conv_result))) { PJ_LOG_ERR("PBNJSON_STR_TO_NUM_ERR", 1, PMLOGKS("STRING", str->m_str), "Some weird problem converting %.*s to a number: %x", (int)str->m_len, str->m_str, conv_result); assert(false); *result = DBL_QUIET_NAN; } else if (UNLIKELY(CONV_HAS_POSITIVE_INFINITY(conv_result))) { *result = HUGE_VAL; } else if (UNLIKELY(CONV_HAS_NEGATIVE_INFINITY(conv_result))) { *result = -HUGE_VAL; } else { if (CONV_HAS_OVERFLOW(conv_result)) { // overflow that isn't infinity is precision loss assert (CONV_HAS_PRECISION_LOSS(conv_result)); } double calculatedWhole = expBase10(wholeComponent, exponent); double calculatedFraction = copysign(expBase10(fraction, exponent - fractionLeadingZeros), calculatedWhole); *result = calculatedWhole + calculatedFraction; if (isinf(*result)) conv_result |= CONV_POSITIVE_OVERFLOW; else if (-isinf(*result)) conv_result |= CONV_NEGATIVE_OVERFLOW; else if (*result == 0 && fraction != 0) conv_result |= CONV_PRECISION_LOSS; } return conv_result; }
void PowerdProxy::ChargerStatusSignal(MojServiceMessage *msg, const MojObject& response, MojErr err) { LOG_TRACE("Entering function %s", __FUNCTION__); LOG_DEBUG("Received charger status signal: %s", MojoObjectJson(response).c_str()); if (err != MojErrNone) { m_chargerStatusSubscribed = false; if (MojoCall::IsPermanentFailure(msg, response, err)) { LOG_WARNING(MSGID_CHRGR_STATUS_SIG_FAIL,0, "Subscription to charger status signal experienced an uncorrectable failure: %s", MojoObjectJson(response).c_str()); m_chargerStatus.reset(); } else { LOG_WARNING(MSGID_CHRGR_SIG_ENABLE,0, "Subscription to charger status signal failed, resubscribing: %s", MojoObjectJson(response).c_str()); EnableChargerSignals(); } return; } if (!m_chargerStatusSubscribed) { m_chargerStatusSubscribed = true; TriggerChargerStatus(); } /* Not all responses will contain charger information... for example, * the initial subscription result. */ MojString chargerType; bool found = false; MojErr err2 = response.get(_T("type"), chargerType, found); if (err2) { LOG_ERROR(MSGID_CHRGR_SIG_NO_TYPE, 1,PMLOGKFV("ERROR","%d",err2), "Error retrieving charger type from charger status signal response"); return; } else if (found) { bool connected; found = response.get(_T("connected"), connected); if (!found) { LOG_WARNING(MSGID_CHRGR_NOT_CONNECTED,1,PMLOGKS("TYPE",chargerType.data()), "Charger type found, but not it's connected"); return; } if (chargerType == "usb") { m_usbChargerConnected = connected; } else if (chargerType == "inductive") { m_inductiveChargerConnected = connected; } else { LOG_WARNING(MSGID_CHRGR_TYPE_UNKNOWN, 1, PMLOGKS("TYPE",chargerType.data()), "Unknown charger type"); return; } found = false; MojString name; err2 = response.get(_T("name"), name, found); if (err2) { LOG_ERROR(MSGID_CHRGR_NO_NAME,2, PMLOGKS("TYPE",chargerType.data()), PMLOGKFV("ERR", "%d", err2), "Error retrieving the specific name of charger"); } else if (found) { if (name == "puck") { m_onPuck = connected; } } if (m_onPuck) { if (!m_dockedRequirementCore->IsMet()) { LOG_DEBUG("Device is now docked"); m_dockedRequirementCore->Met(); std::for_each(m_dockedRequirements.begin(), m_dockedRequirements.end(), boost::mem_fn(&Requirement::Met)); } } else { if (m_dockedRequirementCore->IsMet()) { LOG_DEBUG("Device is no longer docked"); m_dockedRequirementCore->Unmet(); std::for_each(m_dockedRequirements.begin(), m_dockedRequirements.end(), boost::mem_fn(&Requirement::Unmet)); } } if (m_inductiveChargerConnected || m_usbChargerConnected) { if (!m_chargingRequirementCore->IsMet()) { LOG_DEBUG("Device is now charging"); m_chargingRequirementCore->Met(); std::for_each(m_chargingRequirements.begin(), m_chargingRequirements.end(), boost::mem_fn(&Requirement::Met)); } } else { if (m_chargingRequirementCore->IsMet()) { LOG_DEBUG("Device is no longer charging"); m_chargingRequirementCore->Unmet(); std::for_each(m_chargingRequirements.begin(), m_chargingRequirements.end(), boost::mem_fn(&Requirement::Unmet)); } } } }
/** * Main entry point for sleepd - runs the initialization hooks installed at program load time * * A bit counter-intuitively, this is not the first part of this program which * is run. * * First, everything which uses the {@link INIT_FUNC} macro in init.h are run, * which registers a bunch of hooks with the initialization system so that * individual modules can be registered without touching the main sleepd * initialization code. Then, once all of those hooks are installed, execution * proceeds to this function which actually runs those hooks. * * - Initializes sleepd. * - Attaches as a Luna service under com.palm.sleep. * - Attaches to Nyx. * - Subscribes to events related to the charger being plugged and unplugged from the com.palm.power service. * - Calls {@link TheOneInit()} to finish initialization of the service. * - Issues a request to the com.palm.power service to check on the plugged/unplugged status of the charger. * * @param argc Number of command-line arguments. * @param argv List of command-line arguments. * * @todo Move the logging initialization functionality into {@link TheOneInit()}. */ int main(int argc, char **argv) { bool retVal; /* * Register a function to be able to gracefully handle termination signals * from the OS or other processes. */ signal(SIGTERM, term_handler); signal(SIGINT, term_handler); #if !GLIB_CHECK_VERSION(2,32,0) if (!g_thread_supported()) { g_thread_init(NULL); } #endif mainloop = g_main_loop_new(NULL, FALSE); /* * initialize the lunaservice and we want it before all the init * stuff happening. */ LSError lserror; LSErrorInit(&lserror); /* * Register ourselves as the com.palm.sleep service. */ retVal = LSRegisterPalmService("com.palm.sleep", &psh, &lserror); if (retVal) { /* * Attach our main loop to the service so we can process IPC messages addressed to us. */ retVal = LSGmainAttachPalmService(psh, mainloop, &lserror); if (retVal) { /* * Get our private bus for our service so we can pass a message to com.palm.power. */ private_sh = LSPalmServiceGetPrivateConnection(psh); /* * Register with com.palm.power for events regarding changes in status * to the plug/unplug state of any chargers which may be attached to our * device. */ retVal = LSCall(private_sh, "luna://com.palm.lunabus/signal/addmatch", "{\"category\":\"/com/palm/power\"," "\"method\":\"USBDockStatus\"}", ChargerStatus, NULL, NULL, &lserror); if (retVal) { /* * Connect to Nyx so we can use it later. */ int ret = nyx_device_open(NYX_DEVICE_SYSTEM, "Main", &nyxSystem); if (ret != NYX_ERROR_NONE) { SLEEPDLOG_CRITICAL(MSGID_NYX_DEVICE_OPEN_FAIL, 1, PMLOGKS(CAUSE, "Unable to open the nyx device system"), ""); abort(); } /* * Call our main initialization function - this is the function which * is supposed to handle initializing pretty much everything for us. */ TheOneInit(); /* * Now that we've got something listening for charger status changes, * request the current state of the charger from com.palm.power. */ LSCall(private_sh, "luna://com.palm.power/com/palm/power/chargerStatusQuery", "{}", ChargerStatus, NULL, NULL, &lserror); SLEEPDLOG_DEBUG("Sleepd daemon started"); g_main_loop_run(mainloop); } } } else { SLEEPDLOG_CRITICAL(MSGID_SRVC_REGISTER_FAIL, 1, PMLOGKS(ERRTEXT, lserror.message), "Could not initialize sleepd"); LSErrorFree(&lserror); } g_main_loop_unref(mainloop); return 0; }
static void alarm_read_db(void) { bool retVal; xmlDocPtr db = xmlReadFile(gAlarmQueue->alarm_db, NULL, 0); if (!db) { return; } xmlNodePtr cur = xmlDocGetRootElement(db); xmlNodePtr sub; if (!cur) { return; } sub = cur->children; while (sub != NULL) { if (!xmlStrcmp(sub->name, (const xmlChar *)"alarm")) { xmlChar *id = xmlGetProp(sub, (const xmlChar *)"id"); xmlChar *key = xmlGetProp(sub, (const xmlChar *)"key"); xmlChar *expiry = xmlGetProp(sub, (const xmlChar *)"expiry"); xmlChar *calendar = xmlGetProp(sub, (const xmlChar *)"calendar"); xmlChar *service = xmlGetProp(sub, (const xmlChar *)"serviceName"); xmlChar *app = xmlGetProp(sub, (const xmlChar *)"applicationName"); if (!id || !expiry) { goto clean_round; } unsigned long expiry_secs = 0; uint32_t alarmId = 0; bool isCalendar = false; if (expiry) { expiry_secs = atol((const char *)expiry); } if (id) { alarmId = atoi((const char *)id); } if (calendar) { isCalendar = atoi((const char *)calendar) > 0; } retVal = alarm_queue_add(alarmId, (const char *)key, isCalendar, expiry_secs, (const char *)service, (const char *)app, false, NULL); if (!retVal) { SLEEPDLOG_WARNING(MSGID_ALARM_NOT_SET, 3, PMLOGKFV(ALARM_ID, "%d", alarmId), PMLOGKS(SRVC_NAME, service), PMLOGKS(APP_NAME, app), "could not add alarm"); } clean_round: xmlFree(expiry); xmlFree(service); xmlFree(app); } sub = sub->next; } xmlFreeDoc(db); }
void MojoDBProxy::ActivityLoadResults(MojServiceMessage *msg, const MojObject& response, MojErr err) { LOG_TRACE("Entering function %s", __FUNCTION__); LOG_DEBUG("Processing Activities loaded from MojoDB"); /* Don't allow the Activity Manager to start up if the MojoDB load * fails ... */ if (err != MojErrNone) { if (MojoCall::IsPermanentFailure(msg, response, err)) { LOG_ERROR(MSGID_LOAD_ACTIVITIES_FROM_DB_FAIL, 0, "Uncorrectable error loading Activities from MojoDB: %s", MojoObjectJson(response).c_str()); #ifdef ACTIVITYMANAGER_REQUIRE_DB m_app->shutdown(); #else m_app->ready(); #endif } else { LOG_WARNING(MSGID_ACTIVITIES_LOAD_ERR, 0, "Error loading Activities from MojoDB, retrying: %s", MojoObjectJson(response).c_str()); m_call->Call(); } return; } /* Clear current call */ m_call.reset(); bool found; MojErr err2; MojObject results; found = response.get(_T("results"), results); if (found) { for (MojObject::ConstArrayIterator iter = results.arrayBegin(); iter != results.arrayEnd(); ++iter) { const MojObject& rep = *iter; MojInt64 activityId; bool found; found = rep.get(_T("activityId"), activityId); if (!found) { LOG_WARNING(MSGID_ACTIVITYID_NOT_FOUND, 0, "activityId not found loading Activities"); continue; } MojString id; MojErr err = rep.get(_T("_id"), id, found); if (err) { LOG_WARNING(MSGID_RETRIEVE_ID_FAIL, 0, "Error retrieving _id from results returned from MojoDB"); continue; } if (!found) { LOG_WARNING(MSGID_ID_NOT_FOUND, 0, "_id not found loading Activities from MojoDB"); continue; } MojInt64 rev; found = rep.get(_T("_rev"), rev); if (!found) { LOG_WARNING(MSGID_REV_NOT_FOUND, 0, "_rev not found loading Activities from MojoDB"); continue; } boost::shared_ptr<MojoDBPersistToken> pt = boost::make_shared<MojoDBPersistToken>(id, rev); boost::shared_ptr<Activity> act; try { act = m_json->CreateActivity(rep, Activity::PrivateBus, true); } catch (const std::exception& except) { LOG_WARNING(MSGID_CREATE_ACTIVITY_EXCEPTION, 1, PMLOGKS("Exception",except.what()), "Activity: %s", MojoObjectJson(rep).c_str()); m_oldTokens.push_back(pt); continue; } catch (...) { LOG_WARNING(MSGID_UNKNOWN_EXCEPTION, 0, "Activity : %s. Unknown exception decoding encoded", MojoObjectJson(rep).c_str()); m_oldTokens.push_back(pt); continue; } act->SetPersistToken(pt); /* Attempt to register this Activity's Id and Name, in order. */ try { m_am->RegisterActivityId(act); } catch (...) { LOG_ERROR(MSGID_ACTIVITY_ID_REG_FAIL, 1, PMLOGKFV("Activity","%llu", act->GetId()), ""); /* Another Activity is already registered. Determine which * is newer, and kill the older one. */ boost::shared_ptr<Activity> old = m_am->GetActivity( act->GetId()); boost::shared_ptr<MojoDBPersistToken> oldPt = boost::dynamic_pointer_cast<MojoDBPersistToken, PersistToken>(old->GetPersistToken()); if (pt->GetRev() > oldPt->GetRev()) { LOG_WARNING(MSGID_ACTIVITY_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()), PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()), PMLOGKFV("old_Activity","%llu",old->GetId()), PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), ""); m_oldTokens.push_back(oldPt); m_am->UnregisterActivityName(old); m_am->ReleaseActivity(old); m_am->RegisterActivityId(act); } else { LOG_WARNING(MSGID_ACTIVITY_NOT_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()), PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()), PMLOGKFV("old_Activity","%llu",old->GetId()), PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), ""); m_oldTokens.push_back(pt); m_am->ReleaseActivity(act); continue; } } try { m_am->RegisterActivityName(act); } catch (...) { LOG_ERROR(MSGID_ACTIVITY_NAME_REG_FAIL, 3, PMLOGKFV("Activity","%llu",act->GetId()), PMLOGKS("Creator_name",act->GetCreator().GetString().c_str()), PMLOGKS("Register_name",act->GetName().c_str()), ""); /* Another Activity is already registered. Determine which * is newer, and kill the older one. */ boost::shared_ptr<Activity> old = m_am->GetActivity( act->GetName(), act->GetCreator()); boost::shared_ptr<MojoDBPersistToken> oldPt = boost::dynamic_pointer_cast<MojoDBPersistToken, PersistToken>(old->GetPersistToken()); if (pt->GetRev() > oldPt->GetRev()) { LOG_WARNING(MSGID_ACTIVITY_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()), PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()), PMLOGKFV("old_Activity","%llu",old->GetId()), PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), ""); m_oldTokens.push_back(oldPt); m_am->UnregisterActivityName(old); m_am->ReleaseActivity(old); m_am->RegisterActivityName(act); } else { LOG_WARNING(MSGID_ACTIVITY_NOT_REPLACED, 4, PMLOGKFV("Activity","%llu",act->GetId()), PMLOGKFV("revision","%llu",(unsigned long long)pt->GetRev()), PMLOGKFV("old_Activity","%llu",old->GetId()), PMLOGKFV("old_revision","%llu",(unsigned long long)oldPt->GetRev()), ""); m_oldTokens.push_back(pt); m_am->ReleaseActivity(act); continue; } } LOG_DEBUG("[Activity %llu] (\"%s\"): _id %s, rev %llu loaded", act->GetId(), act->GetName().c_str(), id.data(), (unsigned long long)rev); /* Request Activity be scheduled. It won't transition to running * until after the MojoDB load finishes (and the Activity Manager * moves to the ready() and start()ed states). */ m_am->StartActivity(act); } } MojString page; err2 = response.get(_T("page"), page, found); if (err2) { LOG_ERROR(MSGID_GET_PAGE_FAIL, 0, "Error getting page parameter in MojoDB query response"); return; } if (found) { LOG_DEBUG("Preparing to request next page (\"%s\") of Activities", page.data()); MojObject query; query.putString(_T("from"), ActivityKind); query.putString(_T("page"), page); MojObject params; params.put(_T("query"), query); m_call = boost::make_shared<MojoWeakPtrCall<MojoDBProxy> >( boost::dynamic_pointer_cast<MojoDBProxy, PersistProxy> (shared_from_this()), &MojoDBProxy::ActivityLoadResults, m_service, "palm://com.palm.db/find", params); m_call->Call(); } else { LOG_DEBUG("All Activities successfully loaded from MojoDB"); if (!m_oldTokens.empty()) { LOG_DEBUG("Beginning purge of old Activities from database"); PreparePurgeCall(); m_call->Call(); } else { #ifdef ACTIVITYMANAGER_CALL_CONFIGURATOR PrepareConfiguratorCall(); m_call->Call(); #else m_call.reset(); m_am->Enable(ActivityManager::CONFIGURATION_LOADED); #endif } m_app->ready(); } }
ConversionResultFlags parseJSONNumber(raw_buffer *str, int64_t *integerPortion, int64_t *exponentPortion, int64_t *decimalPortion, int64_t *decimalLeadingZeros) { size_t i = 0; int integerMultiplier = 1; int exponentMultiplier = 1; int64_t exponent = 0; int64_t fraction = 0; int64_t fractionFactor = 0; int64_t trailingZeros = 0; bool validDecimal; int64_t temp; ConversionResultFlags result = CONV_OK; *integerPortion = 0; if (str->m_len == 0) { result = CONV_NOT_A_NUM; goto fast_stop; } switch (str->m_str[i]) { case '-': integerMultiplier = -1; i++; goto parse_integer_portion; case '0': i++; if (i >= str->m_len) goto fast_stop; switch(str->m_str[i]) { case '.': goto parse_decimal_portion; case 'e': case 'E': goto parse_exponent_portion; default: result = CONV_NOT_A_NUM; goto fast_stop; } case '1'...'9': goto parse_integer_portion; default: goto not_a_number; } parse_integer_portion: assert(integerMultiplier == 1 || integerMultiplier == -1); assert(exponent == 0); for (; i < str->m_len; i++) { switch (str->m_str[i]) { case 'e': case 'E': goto parse_exponent_portion; case '.': goto parse_decimal_portion; case '0'...'9': if (exponent == 0) { if (integerMultiplier == 1) { if (*integerPortion > (INT64_MAX / 10)) exponent = 1; } else { if (*integerPortion < (INT64_MIN) / 10) exponent = 1; } if (exponent == 0) { temp = *integerPortion * 10 + integerMultiplier * (str->m_str[i] - '0'); if (UNLIKELY(temp * integerMultiplier < 0)) { // sign flipped - overflow exponent = 1; } else { *integerPortion = temp; } } } else { if (exponent++ == INT64_MAX) return CONV_PRECISION_LOSS | (integerMultiplier == 1 ? CONV_POSITIVE_INFINITY : CONV_NEGATIVE_INFINITY); } break; default: PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR1", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i); goto not_a_number; } } goto finish_parse; parse_decimal_portion: validDecimal = false; assert(fraction == 0); assert(fractionFactor == 0); assert(trailingZeros == 0); if (str->m_str[i] != '.') { assert(false); PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR2", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int) str->m_len, str->m_str, i); goto not_a_number; } i++; for (; i < str->m_len; i++) { switch(str->m_str[i]) { case 'e': case 'E': goto parse_exponent_portion; case '0'...'9': validDecimal = true; if (str->m_str[i] == '0') { // short-circuit - trailing 0s are ignored if that's what they are. trailingZeros ++; break; } if (UNLIKELY(fractionFactor == INT64_MAX)) { assert(false); // this will only become an issue if 10^INT64_MAX < (2^((sizeof(fraction)*8) - 1) - 1) // which will never happen PJ_LOG_ERR("PBNJSON_FRACTION_ERR", 1, PMLOGKS("STRING", str->m_str), "Internal error for input: %.*s", (int)str->m_len, str->m_str); return CONV_GENERIC_ERROR; } while (trailingZeros != 0) { temp = fraction * 10; if (temp < 0) goto skip_remaining_decimal; trailingZeros--; fractionFactor++; fraction = temp; } fractionFactor++; if (fraction != INT64_MAX) { temp = fraction * 10 + (str->m_str[i] - '0'); if (UNLIKELY(temp < 0)) { fractionFactor--; goto skip_remaining_decimal; } else { fraction = temp; } } break; default: PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR3", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i); goto not_a_number; } } if (UNLIKELY(!validDecimal)) { PJ_LOG_WARN("PBNJSON_UNXPCTD_EOS", 0, "Unexpected end of string at %zu in '%.*s'", i, (int)str->m_len, str->m_str); goto not_a_number; } goto finish_parse; skip_remaining_decimal: assert(str->m_str[i] >= '0'); assert(str->m_str[i] <= '9'); result |= CONV_PRECISION_LOSS; for (; i < str->m_len; i++) { if (str->m_str[i] >= '0' && str->m_str[i] <= '9') continue; if (str->m_str[i] == 'e' || str->m_str[i] == 'E') goto parse_exponent_portion; PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR4", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i); goto not_a_number; } assert(i == str->m_len); goto finish_parse; parse_exponent_portion: assert(exponent >= 0); if (UNLIKELY(str->m_str[i] != 'e' && str->m_str[i] != 'E')) { // problem with the state machine assert(false); PJ_LOG_ERR("PBNJSON_NO_EXPONENT", 1, PMLOGKS("STRING", str->m_str), "Expecting an exponent but didn't get one at %zu in '%.*s'", i, (int)str->m_len, str->m_str); return CONV_GENERIC_ERROR; } i++; switch (str->m_str[i]) { case '-': i++; exponentMultiplier = -1; break; case '+': i++; case '0'...'9': exponentMultiplier = 1; break; default: PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR5", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i); goto not_a_number; } assert(exponentMultiplier == 1 || exponentMultiplier == -1); for (; i < str->m_len; i++) { switch (str->m_str[i]) { case '0'...'9': if (exponentMultiplier == 1) { if (UNLIKELY(exponent > (INT64_MAX / 10))) goto exponent_overflow; } else if (exponentMultiplier == -1) { if (UNLIKELY(exponent < (INT64_MIN / 10))) goto exponent_overflow; } exponent *= 10; exponent += exponentMultiplier * (str->m_str[i] - '0'); if (exponent * exponentMultiplier < 0) { goto exponent_overflow; } break; default: PJ_LOG_WARN("PBNJSON_PNUM_UNXPCTD_CHAR6", 1, PMLOGKFV("CHAR", "%c", str->m_str[i]), "Unexpected character %d('%c') in '%.*s' at %zu", (int)str->m_str[i], str->m_str[i], (int)str->m_len, str->m_str, i); goto not_a_number; } } assert(i == str->m_len); goto finish_parse; exponent_overflow: // overflow of a 64-bit exponent - +/- infinity or 0 it is. assert(exponent > (INT64_MAX / 10 - 10) || exponent < (INT64_MIN / 10 + 10)); if (exponentMultiplier == 1) { exponent = INT64_MAX; if (integerMultiplier == 1) { *integerPortion = INT64_MAX; result |= CONV_POSITIVE_INFINITY; } else { *integerPortion = INT64_MIN; result |= CONV_NEGATIVE_INFINITY; } } else { result |= CONV_PRECISION_LOSS; exponent = INT64_MIN; *integerPortion = 0; } goto finish_parse; finish_parse: if (trailingZeros) { PJ_LOG_DBG("%"PRId64 " unnecessary 0s in fraction portion of '%.*s'", trailingZeros, (int)str->m_len, str->m_str); } if (fraction == 0) { assert(fractionFactor == 0); } if (*integerPortion == 0 && (decimalPortion == NULL || fraction == 0)) { // shortcut - exponent is redundant if the number is 0.something but we're // ignoring the decimal (or there's no fractional portion) exponent = 0; if (fraction != 0) { result |= CONV_PRECISION_LOSS; } } // can't really do this anyways - it would require us shifting values into or out // of the fractional component when we adjust the integerPortion by the exponent. // internally, we would never use this case anyways because if we care what the // fraction is (i.e. we're converting to a floating point), we'll provide the exponent // pointer anyways if (exponentPortion == NULL && exponent != 0 && fraction != 0) { result |= CONV_PRECISION_LOSS; fraction = 0; fractionFactor = 0; } if (!exponentPortion) { if (*integerPortion != 0) { if (exponent > 0) { while (exponent) { if (*integerPortion > INT64_MAX / 10) { assert(integerMultiplier == 1); result |= CONV_POSITIVE_OVERFLOW; *integerPortion = INT64_MAX; break; } else if (*integerPortion < INT64_MIN / 10) { assert(integerMultiplier == -1); result |= CONV_NEGATIVE_OVERFLOW; *integerPortion = INT64_MIN; break; } if (*integerPortion != 0) assert(*integerPortion * 10 > 0); *integerPortion *= 10; exponent--; } } else if (exponent < 0) { if (fraction) { result |= CONV_PRECISION_LOSS; goto lost_precision; } while (exponent) { if (*integerPortion % 10 != 0) { result |= CONV_PRECISION_LOSS; goto lost_precision; } *integerPortion /= 10; exponent++; } lost_precision: while (exponent++ && *integerPortion > 0) *integerPortion /= 10; } } } else { *exponentPortion = exponent; } if (!decimalPortion) { if (fraction != 0) { result |= CONV_PRECISION_LOSS; } } else { *decimalPortion = fraction; *decimalLeadingZeros = fractionFactor; } return result; not_a_number: return CONV_NOT_A_NUM; fast_stop: if (exponentPortion) *exponentPortion = exponent; if (decimalPortion) *decimalPortion = fraction; if (decimalLeadingZeros) *decimalLeadingZeros = fractionFactor; return result; }
jvalue_ref jdom_parse_file(const char *file, JSchemaInfoRef schemaInfo, JFileOptimizationFlags flags) { CHECK_POINTER_RETURN_NULL(file); CHECK_POINTER_RETURN_NULL(schemaInfo); int fd; off_t fileSize; raw_buffer input = { 0 }; jvalue_ref result; char *err_msg; fd = open(file, O_RDONLY); if (fd == -1) { goto errno_parse_failure; } if (!file_size(fd, &fileSize)) { goto errno_parse_failure; } input.m_len = fileSize; if (input.m_len != fileSize) { PJ_LOG_ERR("PBNJSON_BIG_FILE", 1, PMLOGKS("FILE", file), "File too big - currently unsupported by this API"); close(fd); } if (flags & JFileOptMMap) { input.m_str = (char *)mmap(NULL, input.m_len, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); if (input.m_str == NULL || input.m_str == MAP_FAILED) { goto errno_parse_failure; } } else { input.m_str = (char *)malloc(input.m_len + 1); if (input.m_len != read(fd, (char *)input.m_str, input.m_len)) { goto errno_parse_failure; } ((char *)input.m_str)[input.m_len] = 0; } result = jdom_parse(input, DOMOPT_INPUT_OUTLIVES_WITH_NOCHANGE, schemaInfo); return_result: close(fd); if (UNLIKELY(!jis_valid(result))) { if (input.m_str) { if (flags & JFileOptMMap) { munmap((void *)input.m_str, input.m_len); } else { free((void *)input.m_str); } } } else { result->m_backingBuffer = input; result->m_backingBufferMMap = flags & JFileOptMMap; } return result; errno_parse_failure: err_msg = strdup(strerror(errno)); PJ_LOG_WARN("PBNJSON_PARCE_ERR", 3, PMLOGKS("FILE", file), PMLOGKFV("ERRNO", "%d", errno), PMLOGKS("ERROR", err_msg), "Attempt to parse json document '%s' failed (%d) : %s", file, errno, err_msg); free(err_msg); result = jinvalid(); goto return_result; }