Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0cda289 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7259849 from 746757a0 to sc-v2-release

Change-Id: I99cb4752a9a93cd729aedd25c4f18c28e23bdda6
parents 2127aaea 746757a0
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
//
// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

rust_bindgen {
    name: "libstatspull_bindgen",
    wrapper_src: "statslog.h",
    crate_name: "statspull_bindgen",
    source_stem: "bindings",
    bindgen_flags: [
        "--size_t-is-usize",
        "--whitelist-function=AStatsEventList_addStatsEvent",
        "--whitelist-function=AStatsEvent_.*",
        "--whitelist-function=AStatsManager_.*",
        "--whitelist-var=AStatsManager_.*",
    ],
    target: {
        android: {
            shared_libs: [
                "libstatspull",
                "libstatssocket",
            ],
        },
        host: {
            static_libs: [
                "libstatspull",
                "libstatssocket",
            ],
        },
    },
}

rust_library {
    name: "libstatspull_rust",
    crate_name: "statspull_rust",
    srcs: ["stats_pull.rs"],
    rustlibs: [
        "liblazy_static",
        "liblog_rust",
        "libstatslog_rust_header",
        "libstatspull_bindgen",
    ],
}
+170 −0
Original line number Diff line number Diff line
// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A Rust interface for the StatsD pull API.

use lazy_static::lazy_static;
use statslog_rust_header::{Atoms, Stat, StatsError};
use statspull_bindgen::*;
use std::collections::HashMap;
use std::convert::TryInto;
use std::os::raw::c_void;
use std::sync::Mutex;

/// The return value of callbacks.
pub type StatsPullResult = Vec<Box<dyn Stat>>;

/// A wrapper for AStatsManager_PullAtomMetadata.
/// It calls AStatsManager_PullAtomMetadata_release on drop.
pub struct Metadata {
    metadata: *mut AStatsManager_PullAtomMetadata,
}

impl Metadata {
    /// Calls AStatsManager_PullAtomMetadata_obtain.
    pub fn new() -> Self {
        // Safety: We panic if the memory allocation fails.
        let metadata = unsafe { AStatsManager_PullAtomMetadata_obtain() };
        if metadata.is_null() {
            panic!("Cannot obtain pull atom metadata.");
        } else {
            Metadata { metadata }
        }
    }

    /// Calls AStatsManager_PullAtomMetadata_setCoolDownMillis.
    pub fn set_cooldown_millis(&mut self, cooldown_millis: i64) {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe { AStatsManager_PullAtomMetadata_setCoolDownMillis(self.metadata, cooldown_millis) }
    }

    /// Calls AStatsManager_PullAtomMetadata_getCoolDownMillis.
    pub fn get_cooldown_millis(&self) -> i64 {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe { AStatsManager_PullAtomMetadata_getCoolDownMillis(self.metadata) }
    }

    /// Calls AStatsManager_PullAtomMetadata_setTimeoutMillis.
    pub fn set_timeout_millis(&mut self, timeout_millis: i64) {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe { AStatsManager_PullAtomMetadata_setTimeoutMillis(self.metadata, timeout_millis) }
    }

    /// Calls AStatsManager_PullAtomMetadata_getTimeoutMillis.
    pub fn get_timeout_millis(&self) -> i64 {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe { AStatsManager_PullAtomMetadata_getTimeoutMillis(self.metadata) }
    }

    /// Calls AStatsManager_PullAtomMetadata_setAdditiveFields.
    pub fn set_additive_fields(&mut self, additive_fields: &mut Vec<i32>) {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe {
            AStatsManager_PullAtomMetadata_setAdditiveFields(
                self.metadata,
                additive_fields.as_mut_ptr(),
                additive_fields.len().try_into().expect("Cannot convert length to i32"),
            )
        }
    }

    /// Calls AStatsManager_PullAtomMetadata_getAdditiveFields.
    pub fn get_additive_fields(&self) -> Vec<i32> {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        // We call getNumAdditiveFields to ensure we pass getAdditiveFields a large enough array.
        unsafe {
            let num_fields = AStatsManager_PullAtomMetadata_getNumAdditiveFields(self.metadata)
                .try_into()
                .expect("Cannot convert num additive fields to usize");
            let mut fields = vec![0; num_fields];
            AStatsManager_PullAtomMetadata_getAdditiveFields(self.metadata, fields.as_mut_ptr());
            fields
        }
    }
}

impl Drop for Metadata {
    fn drop(&mut self) {
        // Safety: Metadata::new ensures that self.metadata is a valid object.
        unsafe { AStatsManager_PullAtomMetadata_release(self.metadata) }
    }
}

impl Default for Metadata {
    fn default() -> Self {
        Self::new()
    }
}

lazy_static! {
    static ref COOKIES: Mutex<HashMap<i32, fn() -> StatsPullResult>> = Mutex::new(HashMap::new());
}

// Safety: We store our callbacks in the global so they are valid.
unsafe extern "C" fn callback_wrapper(
    atom_tag: i32,
    data: *mut AStatsEventList,
    _cookie: *mut c_void,
) -> AStatsManager_PullAtomCallbackReturn {
    if !data.is_null() {
        let map = COOKIES.lock().unwrap();
        let cb = map.get(&atom_tag);
        match cb {
            None => log::error!("No callback found for {}", atom_tag),
            Some(cb) => {
                let stats = cb();
                let result = stats
                    .iter()
                    .map(|stat| stat.add_astats_event(&mut *data))
                    .collect::<Result<Vec<()>, StatsError>>();
                match result {
                    Ok(_) => {
                        return AStatsManager_PULL_SUCCESS as AStatsManager_PullAtomCallbackReturn
                    }
                    _ => log::error!("Error adding astats events: {:?}", result),
                }
            }
        }
    }
    AStatsManager_PULL_SKIP as AStatsManager_PullAtomCallbackReturn
}

/// Rust wrapper for AStatsManager_setPullAtomCallback.
pub fn set_pull_atom_callback(
    atom: Atoms,
    metadata: Option<&Metadata>,
    callback: fn() -> StatsPullResult,
) {
    COOKIES.lock().unwrap().insert(atom as i32, callback);
    let metadata_raw = match metadata {
        Some(m) => m.metadata,
        None => std::ptr::null_mut(),
    };
    // Safety: We pass a valid function as the callback.
    unsafe {
        AStatsManager_setPullAtomCallback(
            atom as i32,
            metadata_raw,
            Some(callback_wrapper),
            std::ptr::null_mut(),
        );
    }
}

/// Rust wrapper for AStatsManager_clearPullAtomCallback.
pub fn clear_pull_atom_callback(atom: Atoms) {
    COOKIES.lock().unwrap().remove(&(atom as i32));
    // Safety: No memory allocations.
    unsafe { AStatsManager_clearPullAtomCallback(atom as i32) }
}
+3 −0
Original line number Diff line number Diff line
#pragma once

#include "stats_pull_atom_callback.h"
+22 −0
Original line number Diff line number Diff line
@@ -443,6 +443,20 @@ void RefBase::incStrong(const void* id) const
    refs->mBase->onFirstRef();
}

void RefBase::incStrongRequireStrong(const void* id) const {
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);

    refs->addStrongRef(id);
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);

    LOG_ALWAYS_FATAL_IF(c <= 0 || c == INITIAL_STRONG_VALUE,
                        "incStrongRequireStrong() called on %p which isn't already owned", refs);
#if PRINT_REFS
    ALOGD("incStrong (requiring strong) of %p from %p: cnt=%d\n", this, id, c);
#endif
}

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
@@ -521,6 +535,14 @@ void RefBase::weakref_type::incWeak(const void* id)
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

void RefBase::weakref_type::incWeakRequireWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    LOG_ALWAYS_FATAL_IF(c <= 0, "incWeakRequireWeak called on %p which has no weak refs", this);
}

void RefBase::weakref_type::decWeak(const void* id)
{
+24 −0
Original line number Diff line number Diff line
@@ -241,6 +241,30 @@ TEST(RefBase, ReplacedComparison) {
    ASSERT_FALSE(wp1 != wp2);
}

TEST(RefBase, AssertWeakRefExistsSuccess) {
    // uses some other refcounting method, or non at all
    bool isDeleted;
    sp<Foo> foo = sp<Foo>::make(&isDeleted);
    wp<Foo> weakFoo = foo;

    EXPECT_EQ(weakFoo, wp<Foo>::fromExisting(foo.get()));

    EXPECT_FALSE(isDeleted);
    foo = nullptr;
    EXPECT_TRUE(isDeleted);
}

TEST(RefBase, AssertWeakRefExistsDeath) {
    // uses some other refcounting method, or non at all
    bool isDeleted;
    Foo* foo = new Foo(&isDeleted);

    // can only get a valid wp<> object when you construct it from an sp<>
    EXPECT_DEATH(wp<Foo>::fromExisting(foo), "");

    delete foo;
}

// Set up a situation in which we race with visit2AndRremove() to delete
// 2 strong references.  Bar destructor checks that there are no early
// deletions and prior updates are visible to destructor.
Loading