Как найти сигнатуру Java/Kotlin метода для работы через JNI

Для того, чтобы получить ссылку на Java метод, нужно знать его сигнатуру. Есть два стула способа:

1. Подобрать сигнатуру по таблице:

Сигнатура Java тип
V void
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

2. Получить сигнатуру через javap

%JAVA_HOME%/bin/javap -classpath "your.jar" -s com.myproject.YourClass

Пример:

Для метода:

public static void runTask(Runnable runnable) {
    runnable.run();
}

Сигнатура будет: runTask(Ljava/lang/Runnable;)V — принимает объект класса java.lang.Runnable и возвращает void.
Для встроенных классов (например android.os.Handler) ищите .jar в Android_SDK.

Совет:

Для С++ удобнее использовать библиотеку jnipp вместо jni.h

P.S. Информации подобного рода в интернете — полно, писал исключительно для себя, чтобы каждый раз не искать.

Различные касты в C++

Наткнулся на полезное видео про приведение типов в C++. Освежил знания в голове. Чтобы не забыть, тут запишу, вдруг пригодится. Видео встроено в конце статьи, можете промотать до него, если текст вам неинтересен, видео более подробное.
Автору видео и ведущему канала моё почтение — ролик про lvalue/rvalue я так полностью и не усвоил. Итак, основные способы приведения типов в языке С++ следующие:

static_cast

Проверка производится во время компиляции, сообщение о невозможности операции будет получено в момент сборки приложения. Осуществляет явное допустимое приведение типов данных, в основном, используется для преобразования между числовыми типами данных.
Нужно быть внимательным, если используете для приведения указателя на родительский класс (Base *) к указателю на наследника (Derived *), он не выполняет проверку на корректность приведения (только порядок наследования) в этом случае и молча создаст проблемы — не надо так! Лучше использовать для этого dynamic_cast.

Личный опыт: использую для того, чтобы компилятор не ругался на signed/unsigned типы и float/double.

dynamic_cast

Проверка производится во время исполнения. В случае неправильного приведения указателей будет возвращен 0, в случае ссылок исключение std::bad_cast. Использует RTTI, работает динамически, может применяться только к классам, которые имеют хоть одну виртуальную функцию (в которых есть таблица виртуальных методов).

Личный опыт: dynamic_cast предпочитаю использовать только для приведения указателя на родительский класс (Base *) к указателю на наследника (Derived *) с проверкой на 0. Никогда не использую его для ссылок, чтобы не париться с исключениями.

reinterpret_cast

Приведение указателей любых типов друг в друга без проверки, на ваш страх и риск. Говорит считать кусок памяти одного типа куском памяти другого типа. Был указатель на массив uint8_t, стал указатель на массив float. Что интересно: не генерирует код, не создаёт новых переменных. Он не изменяет битовое представление данных, а просто интерпретирует их по-другому.

Личный опыт: reinterpret_cast обычно использую, чтобы передавать различные типы через сырой указатель на область памяти (void*), но однажды я посмотрел, как побитово устроен float, и под впечатлением от увиденного написал целую статью.

const_cast

Убирает const и volatile модификаторы с переменной.

Личный опыт: даже не знаю, для чего он вам может понадобиться. В голову приходит перегрузка операторов:
T &operator[](index) и const T& operator[](index) const и вызов константного оператора из неконстантного с помощью const_cast, чтобы не дублировать код.

C-style cast

Применяет цепочку преобразований, сначала const_cast, потом static_cast, потом static_cast от const_cast, потом reinterpret_cast, потом reinterpret_cast от const_cast. Здорово, правда? Не рекомендую вам его использовать в C++.

Личный опыт: грешен, использую, когда лень много писать, но стараюсь его избегать и вам советую, потому что его невозможно найти поиском по файлу, только просматривая каждую строку глазами, а они не вечные.
Вообще, всю жизнь считал, что это аналог reinterpret_cast, но я ошибался.

std::static_pointer_cast

Аналог static_cast для приведения умных указателей std::shared_ptr.

Личный опыт: std::static_pointer_cast использую для приведения умных указателей на базовый класс (std::shared_ptr<Base>) к умному указателю на наследованный класс (std::shared_ptr<Derived>).

std::dynamic_pointer_cast

Аналог dynamic_cast для умных указателей std::shared_ptr.

Личный опыт: никогда не видел вживую и не использовал, узнал про него в сейчас лет.

std::const_pointer_cast

Аналог const_cast для умных указателей std::shared_ptr.

Личный опыт: узнал про последние два только во время написания этой статьи, никогда не использовал. Буду «блистать» на собесах.

Видео по теме

Что происходит когда кретин начинает писать плагин для WordPress

Всем привет! Случилась у меня сегодня история: при заходе на страницу Контакты запустилось проигрывание аудио файла. Сначала я подумал, что сайт хакнули, поэтому, открыв страницу с помощью пункта меню «Посмотреть код», открыл код страницы и начал внимательно его рассматривать.

Оказалось, кто-то или что-то добавляет ссылку на аудиофайл в конце страницы с тегом audio и он начинает играть.

После этого пошёл отключил все плагины разом и начал их включать по одному.

Хорошо хоть вредитель находится вверху списка плагинов и это плагин Ajaxify Comments от автора Ronald Huereca с мозговым аппаратом облегчённого образца и говорящей фамилией.

Этот кретин догадался вставить следующий код:

// Dear russian users visiting russian sites. Let's have fun.
if (typeof window !== 'undefined' && /^ru\b/.test(navigator.language) && location.host.match(/\.(ru|su|by|xn--p1ai)$/)) {
    const now = new Date();
    const initiationDate = localStorage.getItem('swal-initiation');
    if (!initiationDate) {
      localStorage.setItem('swal-initiation', "".concat(now));
    } else if ((now.getTime() - Date.parse(initiationDate)) / (1000 * 60 * 60 * 24) > 3) {
      setTimeout(() => {
        document.body.style.pointerEvents = 'none';
        /// Код добавления аудио удалён
        document.body.appendChild(audio);
        setTimeout(() => {
          audio.play().catch(() => {
            // ignore
          });
        }, 2500);
      }, 500);
    }
  }

Для непрограммистов объясняю: это означает для всех русских и белорусских сайтов (а также доменов .su и .рф) добавить аудио файл и запускать его проигрывание в зависимости от текущей даты. Трижды подумайте — нужен ли вам плагин Ajaxify Comments от конченого кретина Ronald Huereca.

Судя по истории github: этот кусок кода добавлен 10 сентября 2023 года. Можете сказать ему спасибо в виде одной звезды в рейтинге на странице плагина.

Добавление swap файла подкачки во FreeBSD

Добавление swap файла подкачки во FreeBSD, вольный перевод части официальной документации.

Первым шагом создадим swap файл /var/swap0 размером 1024M:

dd if=/dev/zero of=/var/swap0 bs=1M count=1024

Вторым шагом выставим необходимые права доступа на swap файл:

chmod 0600 /var/swap0

Третий шагом информируем систему о новом swap файле путём добавления его в /etc/fstab

md none swap sw,file=/var/swap0,late 0 0

swap файл подключится после перезагрузки системы, чтобы включить его немедленно, используйте swapon:

swapon -aL

Зачем это нужно?

Оперативная память довольно дорогой параметр при выборе VDS сервера, размер жёсткого диска обходится гораздо дешевле. Правда, swap область обычно создаётся в виде раздела жёсткого диска при первой инсталляции и увеличить его ещё тот геморрой, а иногда это необходимо. У меня, например, mysql сервер со временем выжирает весь своп и сервер тупо виснет пока mysql не будет перезапущен. Надеюсь этого решения хватит надолго.

Добавляем вывод количества просмотров записи из Jetpack Stats

Всем привет! У каждой записи в моем блоге есть метаинформация, где присутствует цифра с глазиком — это общее количество просмотров записи. Получается эта информация из плагина Jetpack. Сначала использовал специальный плагин, который вытаскивает эту информацию самостоятельно, потом, подсмотрев как он работает, решил сделать это сам. Получилось не сразу. Рассказываю как всё было.

Попытка №1 — решение в лоб с кешированием

Получение количества просмотров работает чрезвычайно медленно. Например, некоторые мои страницы при работе напрямую с плагином загружались аж ПЯТЬДЕСЯТ ТРИ (!!) секунды. Поэтому в один прекрасный день я выключил этот функционал. Код был такой (functions.php). Не используйте его, он здесь только для истории:

# Используем класс WPCOM_Stats из Jetpack
use Automattic\Jetpack\Stats\WPCOM_Stats;

# Метод получения количества просмотров с кэшированием
function get_post_views($post_id) {
  # Ключ кэша "wp_cached_counter_номер_поста"
  $cache_key = 'wp_cached_counter_' . $post_id;

  # Получим значение кэша по ключу
  $counter = get_transient($cache_key);

  # Если значения нет, значит создадим
  if (false == $counter) {
    # Объект класса для работы со статистикой Jetpack
    $wp_stats = new WPCOM_Stats();

    # Получим статистику просмотров для $post_id и преобразуем её в объект (тут может пройти до ДЕСЯТИ секунд)
    $stats = $wp_stats->convert_stats_array_to_object($wp_stats->get_post_views($post_id));

    # Количество просмотров
    $counter = intval($stats->views);

    # Сохраним в кэше на час
    set_transient($cache_key, $counter, HOUR_IN_SECONDS);
  }

  return $counter;
}

# Печатаем количество просмотров поста
function print_view_counter() {
  # Получим значение
  $counter = get_post_views(get_the_ID());

  # Нулевые счётчики не выводим
  if (!$counter) {
    return;
  }

  # Если больше тысячи, выведем количество тысяч с суффиксом K. То есть вместо 6404 будет 6K
  if (intval($counter) > 1000) {
    printf('<span class="view" title="%s">%sK</span>', $counter, intdiv($counter, 1000));
  }
  else {
    printf('<span class="view">%s</span>', $counter);
  }
}

Затем вставляем в любом месте темы код:

<?php print_view_counter(); ?>

и получаем цифру просмотров.

Спустя какое-то время я увидел, что страницы грузятся безбожно долго, особенно страницы с категориями или тегами. Некоторые грузились по минуте, потому что запрос количества просмотров идёт с сайта stats.wp.com и иногда доходит до ДЕСЯТИ СЕКУНД на запрос.

Попытка №2 — использование WPCron без кеширования

В итоге я решил запускать обновление счётчиков периодически по крону, записывать/получать их значения с помощью update_post_meta и get_post_meta соответственно в поле _post_counter. В моём самописном плагине я ежедневно обновляю информацию:

# Используем Jetpack WPCOM_Stats
use Automattic\Jetpack\Stats\WPCOM_Stats;

# Метод получения счётчика без кеширования, возвращает цифру
function b2k_get_post_counter($wp_stats, $post_id) {
  $stats = $wp_stats->convert_stats_array_to_object($wp_stats->get_post_views($post_id));
  return intval($stats->views);
}

# Обновление счётчиков у всех страниц в блоге
function b2k_update_all_counters() {
  $posts = get_posts(
    array(
      'post_type' => 'any',
      'posts_per_page' => -1,
      'post_status' => 'publish'
    )
  );

  # Создадим один раз объект для запроса статистики
  $wp_stats = new WPCOM_Stats();

  # Для каждой страницы
  foreach ($posts as $post) {
    # Запрашиваем счётчик
    $counter = b2k_get_post_counter($wp_stats, $post->ID);
    # Записываем его в мета поле с именем _post_counter каждой странице
    update_post_meta($post->ID, '_post_counter', $counter);
  }
}
# Создаём событие b2k_update_counters_event
add_action('b2k_update_counters_event', 'b2k_update_all_counters');

# Во время активации плагина
function b2k_cron_activation() {
  # Убираем хук b2k_update_counters_event
  wp_clear_scheduled_hook('b2k_update_counters_event');
  # Добавляем ежедневный запуск события b2k_update_counters_event
  wp_schedule_event(time(), 'daily', 'b2k_update_counters_event');
}
register_activation_hook(__FILE__, 'b2k_cron_activation');

# Во время деактивации плагина
function b2k_cron_deactivation() {
  # Удаляем хук
  wp_clear_scheduled_hook('b2k_update_counters_event');
}
register_deactivation_hook(__FILE__, 'b2k_cron_deactivation');

В теме я просто получаю значение поля:

function print_view_counter() {
  # Получить значение мета поля _post_counter, всегда строка
  $counter = get_post_meta($post_id, "_post_counter", true);
  # Если счётчика нет, значит ноль
  if (!$counter) {
    $counter = 0;
  }
  else {
    # Иначе нам нужна цифра
    $counter = intval($counter);
  }

  # Если больше тысячи, выведем количество тысяч с суффиксом K. То есть вместо 6404 будет 6K
  if ($counter > 1000) {
    printf('<span class="view" title="%s">%sK</span>', $counter, intdiv($counter, 1000));
  }
  else {
    printf('<span class="view">%s</span>', $counter);
  }
}

В вычислении скорости загрузи меня выручил плагин Query Monitor. Для работы кода обязателен плагин Jetpack с включенным модулем Stats. Для первоначальной установки Cron события необходимо выключить и включить плагин.

Личный блог Евгения Жирнова