SDK для цифровой персоны — родные проблемы

Я использую в своем приложении Digital Persona SDK для идентификации по отпечатку пальца. Когда я использую функцию идентификации менее чем на 250 fmds, она работает нормально.

Engine.Candidate candidates[] = m_engine.Identify(searchedFmd, 0, fmdArray, DEFAULT_THRESHOLD, 1); //fmdArray < 250

Но с fmdArray> 250 это дает мне собственную ошибку времени выполнения:

A/art: art/runtime/indirect_reference_table.cc:132] JNI ERROR (app bug): local reference table overflow (max=512)

Теперь я запустил это приложение на нескольких устройствах Android и пришел к выводу, что мое приложение падает с fmdArray> 250, когда оно работает на Android 7. Но Android 8 работает нормально. В 8 я могу выполнить проверку даже на 4000 fmds, и все работает нормально.

Но мне нужно запустить этот код на конкретном устройстве, на котором работает Android 7.

Я пытался запустить его всего в пару потоков по 250 fmds. Но после однократного запуска возникает другая проблема с SDK. При втором запуске не работает.

Вот что я делаю: сначала я получаю отпечаток пальца, который хочу идентифицировать:

Reader.CaptureResult capture = m_reader.Capture(fidFormat, UrUSDK.DefaultImageProcessing, m_DPI, timeout);
// In second run, code after this line is not executed.
// My guees its not coming back from native. No exeptions. No errors.
...
Fmd scannedFmd = m_engine.CreateFmd(capture.image, fmdFormat);
...
int index = identifyFinger(fmds, scannedFmd);
...

    private int identifyFinger(List<Fmd> fmdSearchArray, Fmd scannedFmd) {
        List<List<Fmd>> lists = splitToChunks(fmdSearchArray);
        AtomicInteger index = new AtomicInteger(-1);
        List<Callable<Void>> threads = new ArrayList<>(lists.size());
        AtomicInteger iteratorIndex = new AtomicInteger(0);
        for (int i = 0; i < lists.size(); i++) {
            int currentChunk = i;
            Callable<Void> thread = () -> {
                System.out.println(Thread.currentThread().getName() + " with chunk: " + iteratorIndex.getAndIncrement());
                Fmd[] fmds = lists.get(currentChunk).toArray(new Fmd[IDENTIFY_BOUNDARY]);
                try {
                    Engine.Candidate[] candidates = m_engine.Identify(scannedFmd, 0, fmds, threshold, 1);
                    if (candidates.length > 0) {
                        index.set(candidates[0].fmd_index + (currentChunk * IDENTIFY_BOUNDARY));
                    }
                } catch (UareUException e) {

                }
                System.out.println(Thread.currentThread().getName() + " with chunk: " + currentChunk + " finished!");
                return null;
            };
            threads.add(thread);
        }

        try {
            List<Future<Void>> futures = executorService.invokeAll(threads);
            System.out.println("All threads finished: " + index.get());
            return index.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return -1;
        }
    }

...

private List<List<Fmd>> splitToChunks(List<Fmd> fmdSearchArray) {
        int size = fmdSearchArray.size();
        List<List<Fmd>> lists;
        if (size > IDENTIFY_BOUNDARY) {
            int chunks = size / IDENTIFY_BOUNDARY;
            if (size % IDENTIFY_BOUNDARY > 0) {
                chunks++;
            }
            lists = new ArrayList<>(chunks);
            for (int i = 0; i < chunks; i++) {
                if (i + 1 == chunks) {
                    lists.add(new ArrayList<>(fmdSearchArray.subList(i * IDENTIFY_BOUNDARY, size)));
                    break;
                }
                lists.add(new ArrayList<>(fmdSearchArray.subList(i * IDENTIFY_BOUNDARY, (i + 1) * IDENTIFY_BOUNDARY)));
            }
        } else {
            lists = new ArrayList<>(1);
            lists.add(fmdSearchArray);
        }
        return lists;
    }

Проблема с этим кодом в том, что он запускается один раз. Но при другой попытке он не возвращается из собственного кода вызова Caprture.

Итак, мой вопрос: как я могу преодолеть это и заставить его работать из моего java-кода? Или, по крайней мере, каково направление решения?


person Moshe Yamini    schedule 26.04.2020    source источник
comment
Можете ли вы отредактировать свой вопрос, чтобы показать, как вы используете API? Похоже, он не выпускает все свои локальные ссылки.   -  person Botje    schedule 26.04.2020
comment
Почему вы выполняете все запросы параллельно, а не последовательно? Обещает ли SDK безопасность потоков?   -  person Botje    schedule 27.04.2020
comment
Потому что последовательное выполнение займет слишком много времени для идентификации одного отпечатка пальца. Для 4000 fmds это более 3 секунд. Максимум, который мы можем разрешить, составляет ~ 1,4.   -  person Moshe Yamini    schedule 27.04.2020
comment
Затем предложите обсудить с поставщиком SDK, как повысить скорость.   -  person Botje    schedule 27.04.2020


Ответы (1)


Основная причина заключается в том, что эта функция Identify удерживает как минимум две ссылки на каждый возвращенный Candidate после помещения ее в массив результатов. Вместо этого он должен освобождать ссылки после отправки, чтобы его использование (ограниченной) локальной таблицы ссылок оставалось постоянным. Вы должны сообщить об этом.

Самый простой обходной путь на данный момент — разрезать fmdArray на фрагменты размером 250 и вызывать Identify для каждого фрагмента.

person Botje    schedule 27.04.2020
comment
Спасибо. Я отредактировал вопрос, чтобы показать, что я пробовал. И проблема, с которой я столкнулся в этом решении. - person Moshe Yamini; 27.04.2020