Имя: Пароль:
1C
1С v8
Падает внешняя компонента на Android устройстве
, ,
0 Impuls20_03
 
11.03.19
15:09
Здравствуйте коллеги. Пишу внешнюю компоненту на Android. Все работает, все классно, но периодически, при закрытии приложения 1с (примерно 1 раз из 10) приложение вылетает с ошибкой.
Вот, примерно, как выглядит код вызова:

void connect() {
    Initialize(L"com.symbol.datawedge.data_string", L"by.pikant.tsdmk");
    StartAPKMethod();
}

void disconnect() {
    StopAPKMethod();
}

void Initialize(std::wstring messageId, std::wstring intentAction) {
    if (!obj) {
        IAndroidComponentHelper* helper = (IAndroidComponentHelper*)GetInterface(eIAndroidComponentHelper);
        if (helper) {
            jclass ccloc = helper->FindClass(Addin1C::convertStringToPlatform(L"by.pikant.scanreader.TsdProxy").c_str());
            if (ccloc) {
                JNIEnv* env = getJniEnv();
                cc = static_cast<jclass>(env->NewGlobalRef(ccloc));
                env->DeleteLocalRef(ccloc);
                jobject activity = helper->GetActivity();
                jmethodID methID = env->GetMethodID(cc, "<init>", "(Landroid/app/Activity;JLjava/lang/String;Ljava/lang/String;)V");
                jstring mId = wsz2jstr(messageId);
                jstring IA  = wsz2jstr(intentAction);
                jobject objloc = env->NewObject(cc, methID, activity, (jlong)this, (jstring)mId, (jstring)IA);
                env->DeleteLocalRef(mId);
                env->DeleteLocalRef(IA);
                obj = static_cast<jobject>(env->NewGlobalRef(objloc));
                env->DeleteLocalRef(objloc);
                methID = env->GetMethodID(cc, "show", "()V");
                env->CallVoidMethod(obj, methID);
                env->DeleteLocalRef(activity);
            }
        }
    }
}
void StartAPKMethod(){
    if (obj){
        JNIEnv* env = getJniEnv();
        jmethodID methID = env->GetMethodID(cc, "start", "()V");
        env->CallVoidMethod(obj, methID);
    }
}
void StopAPKMethod(){
    if (obj) {
        JNIEnv* env = getJniEnv();
        jmethodID methID = env->GetMethodID(cc, "stop", "()V");
        env->CallVoidMethod(obj, methID);
        if (obj)
        env->DeleteGlobalRef(obj);
        if (cc)
            env->DeleteGlobalRef(cc);
        obj = nullptr;
        cc = nullptr;
    }
}

Локализовал ошибку до метода StopAPKMethod(). Если в цикле подергать методы connect(), disconnect() раз 100 - то приложение обязательно упадет с трассировкой стека:

* * * * * * * * * * * * * * * *
Build fingerprint: 'Xiaomi/santoni/santoni:7.1.2/N2G47H/V10.1.1.0.NAMMIFI:user/release-keys'
Revision: '0'
ABI: 'arm'
pid: 30771, tid: 30794, name: pool-1-thread-1  >>> by.pikant.testVK <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
    r0 c4dae8e0  r1 c4dae8e0  r2 00000001  r3 00000000
    r4 c4dae8e0  r5 c767e7dc  r6 c767e65c  r7 cae8dfbc
    r8 00000000  r9 c7c18000  sl 00000010  fp 00000000
    ip c93e8ec5  sp c767e608  lr c8680cf5  pc c873d528  cpsr 800f0030

backtrace:
    #00 pc 005ae528  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #01 pc 004f1cf3  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #02 pc 01259ed7  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #03 pc 015075b3  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #04 pc 015083a9  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #05 pc 0150cdcf  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #06 pc 0151608f  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #07 pc 01521a55  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #08 pc 01522b95  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #09 pc 0152e815  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #10 pc 0152f3cf  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #11 pc 0073d5fb  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #12 pc 0073b487  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #13 pc 007ac5f5  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #14 pc 007b9e3b  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #15 pc 006bc153  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #16 pc 006bc1b9  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #17 pc 006b9ed5  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #18 pc 006bb613  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #19 pc 00692771  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #20 pc 006a37a9  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #21 pc 006a3d19  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #22 pc 006925bf  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #23 pc 006a19d5  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #24 pc 007c82b3  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #25 pc 007c8769  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #26 pc 00e8bc2d  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #27 pc 00e8bd3d  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #28 pc 01b49737  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #29 pc 005a664b  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #30 pc 005a6f77  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #31 pc 005a5417  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #32 pc 01b48513  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #33 pc 01b4856d  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #34 pc 01b60d51  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #35 pc 01b60e39  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #36 pc 004ea9b5  /data/app/by.pikant.testVK-1/lib/arm/lib1cem.so
    #37 pc 0046ffed  /data/app/by.pikant.testVK-1/oat/arm/base.odex (offset 0x45e000)

Код самого APK тривиален:

package by.pikant.scanreader;

import android.app.Activity;
import android.content.IntentFilter;

public class TsdProxy implements Runnable  {

    private Activity mActivity;     // custom activity of 1C:Enterprise
    private ProxyReceiver mReceiver;
    private String mIntentAction;   // Название интента, который предполагается получить. Задается в программе управления ТСД.

    public TsdProxy(Activity activity, long v8Object, String vMessageId, String vIntentAction){
        mActivity       = activity;
        mIntentAction   = vIntentAction;

        mReceiver       = new ProxyReceiver();
        //"com.symbol.datawedge.data_string"
        mReceiver.setScannerMessageID(vMessageId);      // Идентификатор строки, которая передается сканером через Intent. Для Zebra это: com.symbol.datawedge.data_string
        mReceiver.setV8Object(v8Object);                // Ссылка на объект внешней компоненты
    }

    public void run() {
        System.loadLibrary("libNativeComponent");       // Загружаем библиотеку внешней компоненты
    }

    public void show() {
        mActivity.runOnUiThread(this);
    }

    public void start() {
        if (mReceiver != null) {
            mActivity.registerReceiver(mReceiver, new IntentFilter(mIntentAction)); //"by.pikant.tsdmk"
        }
    }

    public void stop() {
        if (mReceiver != null) {
            mActivity.unregisterReceiver(mReceiver);
        }
    }
}

Очевидно что я упускаю какую-то деталь, но уловить ее package by.pikant.scanreader;

import android.app.Activity;
import android.content.IntentFilter;

public class TsdProxy implements Runnable  {

    private Activity mActivity;     // custom activity of 1C:Enterprise
    private ProxyReceiver mReceiver;
    private String mIntentAction;   // Название интента, который предполагается получить. Задается в программе управления ТСД.

    public TsdProxy(Activity activity, long v8Object, String vMessageId, String vIntentAction){
        mActivity       = activity;
        mIntentAction   = vIntentAction;

        mReceiver       = new ProxyReceiver();
        //"com.symbol.datawedge.data_string"
        mReceiver.setScannerMessageID(vMessageId);      // Идентификатор строки, которая передается сканером через Intent. Для Zebra это: com.symbol.datawedge.data_string
        mReceiver.setV8Object(v8Object);                // Ссылка на объект внешней компоненты
    }

    public void run() {
        System.loadLibrary("libNativeComponent");                   // Загружаем библиотеку внешней компоненты
    }

    public void show() {
        mActivity.runOnUiThread(this);
    }

    public void start() {
        if (mReceiver != null) {
            mActivity.registerReceiver(mReceiver, new IntentFilter(mIntentAction)); //"by.pikant.tsdmk"
        }
    }

    public void stop() {
        if (mReceiver != null) {
            mActivity.unregisterReceiver(mReceiver);
        }
    }
}

Буду благодарен за помощь
1 PloAl
 
11.03.19
16:02
Попробуйте добавить mReceiver = null в

public void stop() {
    if (mReceiver != null) {
        mActivity.unregisterReceiver(mReceiver);
        mReceiver = null;
    }
}
2 Impuls20_03
 
11.03.19
16:09
(1) Пробовал. Не помогает. Пробовал удалять вообще весь код из APK и оставлял только скелет программы. Все равно падает. Проблема именно в методе StopAPKMethod();
3 Кирпич
 
11.03.19
16:34
может getJniEnv() возвращает null и пошло поехало
4 PloAl
 
11.03.19
16:40
Тогда скорее всего проблема в коде с++ где описываются методы и свойства ВК или вызывается:

void disconnect() {
    StopAPKMethod();
}
5 Impuls20_03
 
11.03.19
16:50
(3) Увы мимо. Дополнил код проверками. Легче не стало.
(4) Возможно код и не идеален, но он прекрасно работает без jni вызовов.
Вообще складывается четкое впечатление, что всем этим безобразием рулит 1с-ка, и, иногда, сборщик мусора успевает добраться до моих переменных раньше чем я.
6 Сияющий в темноте
 
11.03.19
21:28
(5)там было описание проблемы из-за того,что сборщик мусора на может остановить выполнение нативного кода,то они выполняются параллельно,что и может приводить к очень интересным результатам.
7 H A D G E H O G s
 
12.03.19
12:27
А что в функции
wsz2jstr()
?
8 Impuls20_03
 
12.03.19
12:50
(7)     static jstring wsz2jstr(std::wstring cstr) {
        JNIEnv* env = getJniEnv();
        Addin1C::platformString str = Addin1C::convertStringToPlatform(cstr);
        int len = str.size();
        jchar* raw = new jchar[len];
        memcpy(raw, str.c_str(), len * sizeof(wchar_t));
        jstring result = env->NewString(raw, len);
        delete[] raw;
        return result;
    }
9 H A D G E H O G s
 
12.03.19
13:00
(8) А
convertStringToPlatform() ?
10 H A D G E H O G s
 
12.03.19
13:02
Я просто делаю через
std::wstring->std::string->char*->NewStringUTF()

Шо в 1С utf-8, шо в Android
11 Impuls20_03
 
12.03.19
13:23
(10)

typedef WCHAR_T platformChar;
typedef std::basic_string<platformChar> platformString;

inline platformString convertStringToPlatform(const std::wstring& source) {
#ifdef _WINDOWS
    return source;
#else
    return platformString(source.cbegin(), source.cend());
#endif
}
12 H A D G E H O G s
 
12.03.19
13:29
(11) Тогда мои подозрения не оправдались
13 H A D G E H O G s
 
12.03.19
14:06
(11) Смогли подключиться отладчиком к native части?
14 Impuls20_03
 
12.03.19
16:57
(13) О. Если бы я знал как. so библиотека писана на Visual Studio, apk на Android Studio. Как подключиться отладчиком ко всему этому добру я не знаю. Вроде из VS можно подрубиться к DLL на винде, и ее отладить, а вот как это сделать на андроиде я вообще без понятия. Буду очень благодарен если направите куда нужно
15 H A D G E H O G s
 
12.03.19
18:22
(14) Я пострадал пару дней и забил.
Даже собрал apk Мобильной 1С с сервером отладки gbdserver и поставил VisualGBD. Но не шмогла.
Кто-нибудь отлаживал NDK (С++, неуправляемый код) Android через VisualGBD ?

Поэтому покрыл код вызовом трассировок вида:
_trace("trc_Step2.8N_GetClass_com.ASF.ScanCodeTransportMC.ScanCode");
где

void _trace(const char* format)
{
    
    if (istraceenable == false)
    {
        return;
    }

    trace(format);
}

где trace() - экспортная функция из jnienv.cpp
16 H A D G E H O G s
 
12.03.19
18:24
По хорошему, надо попробовать native блок развернуть на Ведроиде, вдруг там отладка прокнет.

А вообще по хорошему - портировать на Дельфи и жить как раньше.
17 Impuls20_03
 
13.03.19
08:35
(15) Да. Это, похоже, самый толковый вариант.
18 H A D G E H O G s
 
19.03.19
23:19
Перетащил полностью на ведроид студио.
И как бэ - нет. Не работает отладка.
Хотя на примере из коробки - работает.

Причина - проста.

Сначало 1С загружает so-либу из макета, а потом apk.
А Ведроид пакует so -либу в apk и ждет ее версию на отладку.

Короче, получается, что есть 2 одинаковые so либы, одну загружает 1С, другую ждет Ведроид.

Завтра попробую разобрать apk и удалить из него so либу, теоретически, это должно сработать.
19 H A D G E H O G s
 
19.03.19
23:20
Много радостных сношений вас ждет с CMakeList.txt, бойтесь его.
20 H A D G E H O G s
 
20.03.19
17:57
Короче, есть отладка native c++ из Ведроида
21 H A D G E H O G s
 
20.03.19
17:58
Ооо, сколько интересного и необычного ждет ребят на пути создания ВнешнихКомпонент под мобильный клиент.
22 H A D G E H O G s
 
20.03.19
18:00
Я просто оставлю это здесь
http://prntscr.com/n0jimu
23 Garykom
 
гуру
20.03.19
18:58
(21) Напиши плиз мануал для будущих поколений
24 H A D G E H O G s
 
21.03.19
10:42
(23) Будет время, напишу.
26 MegaKent
 
29.05.19
01:25
(22) а исходником можешь поделитсо ?
надо норм драйвер для zebra mc33 запилить