blob: 811ff6f6097751c19f6827ce6fc784777d31083f [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/metrics/public/cpp/ukm_source_id.h"
#include <cmath>
#include <string>
#include "base/atomic_sequence_num.h"
#include "base/check.h"
#include "base/check_op.h"
#include "base/rand_util.h"
namespace ukm {
namespace {
const int64_t kLowBitsMask = (INT64_C(1) << 32) - 1;
int64_t GetNumTypeBits() {
return std::ceil(
std::log2(static_cast<int64_t>(SourceIdObj::Type::kMaxValue) + 1));
}
} // namespace
// static
SourceIdObj SourceIdObj::New() {
// Generate some bits which are unique to this process, so we can generate
// IDs independently in different processes. IDs generated by this method may
// collide, but it should be sufficiently rare enough to not impact data
// quality.
const static int64_t process_id_bits =
static_cast<int64_t>(base::RandUint64()) & ~kLowBitsMask;
// Generate some bits which are unique within the process, using a counter.
static base::AtomicSequenceNumber seq;
SourceIdObj local_id =
FromOtherId(seq.GetNext() + 1, SourceIdObj::Type::DEFAULT);
// Combine the local and process bits to generate a unique ID.
return SourceIdObj((local_id.value_ & kLowBitsMask) | process_id_bits);
}
// static
SourceIdObj SourceIdObj::FromOtherId(int64_t other_id, SourceIdObj::Type type) {
// Note on syntax: std::ceil and std::log2 are not constexpr functions thus
// these variables cannot be initialized statically in the global scope above.
// Function static initialization here is thread safe; so they are initialized
// at most once.
static const int64_t kNumTypeBits = GetNumTypeBits();
static const int64_t kTypeMask = (INT64_C(1) << kNumTypeBits) - 1;
const int64_t type_bits = static_cast<int64_t>(type);
DCHECK_EQ(type_bits, type_bits & kTypeMask);
// Stores the type of the source ID in its lower bits, and shift the rest of
// the ID to make room. This could cause the original ID to overflow, but
// that should be rare enough that it won't matter for UKM's purposes.
return SourceIdObj((other_id << kNumTypeBits) | type_bits);
}
SourceIdObj::Type SourceIdObj::GetType() const {
static const int64_t kNumTypeBits = GetNumTypeBits();
static const int64_t kTypeMask = (INT64_C(1) << kNumTypeBits) - 1;
return static_cast<SourceIdObj::Type>(value_ & kTypeMask);
}
SourceId AssignNewSourceId() {
return ukm::SourceIdObj::New().ToInt64();
}
SourceId ConvertToSourceId(int64_t other_id, SourceIdType id_type) {
// DCHECK is to restrict the usage of WEBAPK_ID, PAYMENT_APP_ID, and
// WEB_IDENTITY_ID. These should use the specific
// |UkmRecorder::GetSourceIdFor*() methods instead.
// TODO(crbug.com/1046964): Ideally we should restrict
// SourceIdObj::FromOtherId() as well.
DCHECK(id_type != SourceIdType::WEBAPK_ID);
DCHECK(id_type != SourceIdType::PAYMENT_APP_ID);
DCHECK(id_type != SourceIdType::WEB_IDENTITY_ID);
return ukm::SourceIdObj::FromOtherId(other_id, id_type).ToInt64();
}
SourceIdType GetSourceIdType(SourceId source_id) {
return ukm::SourceIdObj::FromInt64(source_id).GetType();
}
std::string GetSourceIdTypeDebugString(SourceId source_id) {
const auto source_type = GetSourceIdType(source_id);
switch (source_type) {
case SourceIdObj::Type::DEFAULT:
return "DEFAULT";
case SourceIdObj::Type::NAVIGATION_ID:
return "NAVIGATION_ID";
case SourceIdObj::Type::APP_ID:
return "APP_ID";
case SourceIdObj::Type::HISTORY_ID:
return "HISTORY_ID";
case SourceIdObj::Type::WEBAPK_ID:
return "WEBAPK_ID";
case SourceIdObj::Type::PAYMENT_APP_ID:
return "PAYMENT_APP_ID";
case SourceIdObj::Type::DESKTOP_WEB_APP_ID:
return "DESKTOP_WEB_APP_ID";
case SourceIdObj::Type::WORKER_ID:
return "WORKER_ID";
case SourceIdObj::Type::NO_URL_ID:
return "NO_URL_ID";
case SourceIdObj::Type::REDIRECT_ID:
return "REDIRECT_ID";
case SourceIdObj::Type::WEB_IDENTITY_ID:
return "WEB_IDENTITY_ID";
case SourceIdObj::Type::CHROMEOS_WEBSITE_ID:
return "CHROMEOS_WEBSITE_ID";
case SourceIdObj::Type::EXTENSION_ID:
return "EXTENSION_ID";
}
}
SourceId NoURLSourceId() {
static const SourceId source_id =
SourceIdObj::FromOtherId(AssignNewSourceId(), SourceIdType::NO_URL_ID)
.ToInt64();
return source_id;
}
} // namespace ukm