void InlineResult::report()
{
    // User may have suppressed reporting via setReported(). If so, do nothing.
    if (inlReported)
    {
        return;
    }

    inlReported = true;

#ifdef DEBUG

    // Optionally dump the result
    if (VERBOSE)
    {
        const char* format = "INLINER: during '%s' result '%s' reason '%s' for '%s' calling '%s'\n";
        const char* caller = (inlCaller == nullptr) ? "n/a" : inlCompiler->eeGetMethodFullName(inlCaller);
        const char* callee = (inlCallee == nullptr) ? "n/a" : inlCompiler->eeGetMethodFullName(inlCallee);

        JITDUMP(format, inlContext, resultString(), reasonString(), caller, callee);
    }

    // If the inline failed, leave information on the call so we can
    // later recover what observation lead to the failure.
    if (isFailure() && (inlCall != nullptr))
    {
        // compiler should have revoked candidacy on the call by now
        assert((inlCall->gtFlags & GTF_CALL_INLINE_CANDIDATE) == 0);

        inlCall->gtInlineObservation = static_cast<unsigned>(inlObservation);
    }

#endif // DEBUG

    if (isDecided())
    {
        const char* format = "INLINER: during '%s' result '%s' reason '%s'\n";
        JITLOG_THIS(inlCompiler, (LL_INFO100000, format, inlContext, resultString(), reasonString()));
        COMP_HANDLE comp = inlCompiler->info.compCompHnd;
        comp->reportInliningDecision(inlCaller, inlCallee, result(), reasonString());
    }
}
static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jintArray outIrqs,
        jobjectArray outReasons)
{
    bool first_time = false;

    if (outIrqs == NULL || outReasons == NULL) {
        jniThrowException(env, "java/lang/NullPointerException", "null argument");
        return -1;
    }

    // Register our wakeup callback if not yet done.
    if (!wakeup_init) {
        wakeup_init = true;
        ALOGV("Creating semaphore...");
        int ret = sem_init(&wakeup_sem, 0, 0);
        if (ret < 0) {
            char buf[80];
            strerror_r(errno, buf, sizeof(buf));
            ALOGE("Error creating semaphore: %s\n", buf);
            jniThrowException(env, "java/lang/IllegalStateException", buf);
            return -1;
        }
        ALOGV("Registering callback...");
        set_wakeup_callback(&wakeup_callback);
        // First time through, we will just drain the current wakeup reasons.
        first_time = true;
    } else {
        // On following calls, we need to wait for wakeup.
        ALOGV("Waiting for wakeup...");
        int ret = sem_wait(&wakeup_sem);
        if (ret < 0) {
            char buf[80];
            strerror_r(errno, buf, sizeof(buf));
            ALOGE("Error waiting on semaphore: %s\n", buf);
            // Return 0 here to let it continue looping but not return results.
            return 0;
        }
    }

    FILE *fp = fopen(LAST_RESUME_REASON, "r");
    if (fp == NULL) {
        ALOGE("Failed to open %s", LAST_RESUME_REASON);
        return -1;
    }

    int numOut = env->GetArrayLength(outIrqs);
    ScopedIntArrayRW irqs(env, outIrqs);

    ALOGV("Reading up to %d wakeup reasons", numOut);

    char mergedreason[MAX_REASON_SIZE];
    char* mergedreasonpos = mergedreason;
    int remainreasonlen = MAX_REASON_SIZE;
    int firstirq = 0;
    char reasonline[128];
    int i = 0;
    while (fgets(reasonline, sizeof(reasonline), fp) != NULL && i < numOut) {
        char* pos = reasonline;
        char* endPos;
        // First field is the index.
        int irq = (int)strtol(pos, &endPos, 10);
        if (pos == endPos) {
            // Ooops.
            ALOGE("Bad reason line: %s", reasonline);
            continue;
        }
        pos = endPos;
        // Skip whitespace; rest of the buffer is the reason string.
        while (*pos == ' ') {
            pos++;
        }
        // Chop newline at end.
        char* endpos = pos;
        while (*endpos != 0) {
            if (*endpos == '\n') {
                *endpos = 0;
                break;
            }
            endpos++;
        }
        // For now we are not separating out the first irq.
        // This is because in practice there are always multiple
        // lines of wakeup reasons, so it is better to just treat
        // them all together as a single string.
        if (false && i == 0) {
            firstirq = irq;
        } else {
            int len = snprintf(mergedreasonpos, remainreasonlen,
                    i == 0 ? "%d" : ":%d", irq);
            if (len >= 0 && len < remainreasonlen) {
                mergedreasonpos += len;
                remainreasonlen -= len;
            }
        }
        int len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos);
        if (len >= 0 && len < remainreasonlen) {
            mergedreasonpos += len;
            remainreasonlen -= len;
        }
        // For now it is better to combine all of these in to one entry in the
        // battery history.  In the future, it might be nice to figure out a way
        // to efficiently store multiple lines as a single entry in the history.
        //irqs[i] = irq;
        //ScopedLocalRef<jstring> reasonString(env, env->NewStringUTF(pos));
        //env->SetObjectArrayElement(outReasons, i, reasonString.get());
        //ALOGV("Wakeup reason #%d: irw %d reason %s", i, irq, pos);
        i++;
    }

    ALOGV("Got %d reasons", i);
    if (first_time) {
        i = 0;
    }
    if (i > 0) {
        irqs[0] = firstirq;
        *mergedreasonpos = 0;
        ScopedLocalRef<jstring> reasonString(env, env->NewStringUTF(mergedreason));
        env->SetObjectArrayElement(outReasons, 0, reasonString.get());
        i = 1;
    }

    if (fclose(fp) != 0) {
        ALOGE("Failed to close %s", LAST_RESUME_REASON);
        return -1;
    }

    return first_time ? 0 : i;
}
	void Tracker::Update(TrackerEvent event)
	{
		auto announce = HTTP::ParseURL(m_AnnounceURL);
		LOG_F("Querying \"%\"", announce.authority);

		announce.arguments["info_hash"] = url_encode((unsigned char*)m_InfoHash.c_str());
		announce.arguments["peer_id"] = m_PeerID;
		announce.arguments["port"] = "6881";

		switch (event)
		{
		case TrackerEvent::Started:
			announce.arguments["event"] = "started";
			break;
		case TrackerEvent::Stopped:
			announce.arguments["event"] = "stopped";
			break;
		case TrackerEvent::Completed:
			announce.arguments["event"] = "completed";
			break;
		}

		auto response = HTTP::DoHTTPRequest(announce);

		if (response.statusCode != 200)
		{
			LOG_F("Tracker request failed (HTTP error): %", response.statusCode);
			return;
		}

		auto parsed = std::make_unique<Bencode::Dictionary>(Bencode::Tokenizer::Tokenize(response.content));

		if (parsed->GetKey("failure reason") != nullptr)
		{
			auto reason = parsed->GetKey<Bencode::ByteString>("failure reason");
			auto bytes = reason->GetBytes();
			std::string reasonString(bytes.begin(), bytes.end());
			LOG_F("Tracker request failed (tracker error): %", reasonString);
			return;
		}

		auto peersCount = 0u;

		auto peersList = (Bencode::List*)(parsed->GetKey("peers").get());
		for (auto& peerObject : peersList->GetObjects())
		{
			auto peerDict = (Bencode::Dictionary*)peerObject.get();

			auto ipBytes = ((Bencode::ByteString*)peerDict->GetKey("ip").get())->GetBytes();
			auto port = ((Bencode::Integer*)peerDict->GetKey("port").get())->GetValue();
			auto idBytes = ((Bencode::ByteString*)peerDict->GetKey("peer id").get())->GetBytes();

			std::string ip(ipBytes.data(), ipBytes.size());

			std::ostringstream oss;
			oss << std::setfill('0');
			std::for_each(ipBytes.begin(), ipBytes.end(), bin2hex_str(oss));
			auto id = oss.str();

			if (m_Known.find(ip) == m_Known.end())
			{
				peersCount++;
				m_Peers.push_back(std::make_unique<Peer>(ip, (int)port, id, m_Client->GetPiecesCount(), m_Client->GetPieceLength(), m_InfoHash, m_PeerID));
				m_Known.insert(ip);
			}
		}

		LOG_F("Request successful, got % peers", peersCount);
	}