* * *

Author Topic: Android JNI Thread  (Read 1353 times)

tommy_rusev

  • New member
  • *
  • Posts: 5
Android JNI Thread
« on: January 22, 2018, 06:21:29 am »
 :(There is one project for Android realized with Lazarus and android native controls (JNI).
I have a small problem with android native controls (JNI) all works perfectly until the time I had to use threads.
I notice that a problem arises when more than one thread (main thread and second thread) are executed simultaneously. For a long time I have tried to solve the problem but unsuccessfully.

Java side
Code: Java  [Select]
  1. class jThread extends Thread {
  2.     private boolean         mSynchronize = false;
  3.     private boolean         mPaused      = false;
  4.     private Object          mPauseLock   = null;
  5.     private int             PasObj       = 0;      // Pascal Obj
  6.     private Controls        controls     = null;   // Control Class for Event
  7.     public  boolean         mRun         = false;
  8.  
  9.     public jThread(Controls ctrls, int pasobj)
  10.     {
  11.         PasObj   = pasobj;
  12.         controls = ctrls;
  13.         mPauseLock = new Object();
  14.     }
  15.  
  16.     @Override
  17.     public void run()
  18.     {
  19.         mRun = true;
  20.         controls.jOnThread(PasObj, Const.Thread_Begin);
  21.         try {
  22.             controls.jOnThread(PasObj, Const.Thread_Execute);
  23.         } catch (Exception e) {
  24.             //String error = new String("Run: "+e.toString()+"\n");
  25.             //controls.ErrorLog.FileWrite(error.getBytes(),error.getBytes().length);
  26.         }
  27.         controls.jOnThread(PasObj, Const.Thread_End);
  28.         mRun = false;
  29.     }
  30.  
  31.     public  void Synchronize(boolean sleep) {
  32.         mSynchronize = true;
  33.  
  34.         new Handler(Looper.getMainLooper()).post(new Runnable() {
  35.             public void run() {
  36.                 controls.jOnThread(PasObj, Const.Thread_Synchronize);
  37.                 mSynchronize = false;
  38.             }
  39.         });
  40.  
  41.         do {
  42.             try {
  43.                 Thread.sleep(1);
  44.             } catch (InterruptedException e) {
  45.             }
  46.             if (!mSynchronize) {break;};
  47.         }
  48.         while (true);
  49.     }
  50.  
  51.     public  void Resume() {
  52.         synchronized (mPauseLock) {
  53.             mPaused = false;
  54.             mPauseLock.notifyAll();
  55.         }
  56.     }
  57.  
  58.     public  void Suspend() {
  59.         mPaused = true;
  60.         synchronized (mPauseLock) {
  61.             while (mPaused) {
  62.                 try {
  63.                     mPauseLock.wait();
  64.                 } catch (InterruptedException e) {
  65.                 }
  66.             }
  67.         }
  68.     }
  69.  
  70.     public  void Sleep(int Milliseconds) {
  71.         try {
  72.             Thread.sleep(Milliseconds);
  73.         } catch (InterruptedException e) {
  74.  
  75.         }
  76.     }
  77.  
  78.     public  void Free() {
  79.         mPauseLock = null;
  80.     }
  81. }
  82.  


Pascal and_function side
Code: Pascal  [Select]
  1. Procedure Java_Event_pOnThread(env: PJNIEnv; this: jobject;
  2.                                Obj: TObject; Mode:Integer); cdecl;
  3. var
  4.  fEnv : PJNIEnv;
  5.  ID:pthread_t;
  6.  I,Index:integer;
  7. begin
  8.  if not (Assigned(Obj)) then Exit;
  9.  
  10.  case TThreadMode(Mode) of
  11.   Thread_Begin:
  12.    begin
  13.     dbg('Java_Event_pOnThread begin');
  14.     Exit;
  15.    end;
  16.   Thread_End:
  17.    begin
  18.     dbg('Java_Event_pOnThread end');
  19.     Exit;
  20.    end;
  21.   Thread_Execute:
  22.    begin
  23.     dbg('Java_Event_pOnThread execute1');
  24.     if Obj is TThread then TThread(Obj).GenEvent_OnThread(TThreadMode(Mode));
  25.     dbg('Java_Event_pOnThread execute2');
  26.    end;
  27.   Thread_Synchronize:  
  28.    begin
  29.     dbg('Java_Event_pOnThread synchronize1');
  30.     if Obj is TThread then TThread(Obj).GenEvent_OnThread(TThreadMode(Mode));
  31.     dbg('Java_Event_pOnThread synchronize2');
  32.    end;
  33.  end;
  34. end;
  35.  
  36. Function jGetMethodID(var Env : PJNIEnv; var jControls:jobject; FuncName, FuncSig : PChar) : jMethodID;
  37. var
  38.  jClass : jobject;
  39. begin
  40.  Result := nil;
  41.  Env:=nil;
  42.  gApp.jVM^.AttachCurrentThread(gApp.jVM,@Env,nil);
  43.  if (Env = nil) then
  44.  begin
  45.   dbgf(PChar(FuncName+' ('+IntToStr(gettid)+') Env = nil'));
  46.   Exit;
  47.  end;
  48.  dbg(Pchar(FuncName+'  ('+IntToStr(gettid)+')'));
  49.  jClass := Env^.FindClass(Env,_cAppC);
  50.  if (jClass = nil) then
  51.  begin
  52.   dbge(PChar(FuncName+'  ('+IntToStr(gettid)+') jClass = nil'));
  53.   Exit;
  54.  end;
  55.  Result := Env^.GetMethodID(Env, jClass, FuncName, FuncSig);
  56.  Env^.DeleteLocalRef(Env,jClass);
  57.  jControls:=gApp.jControls;
  58. end;
  59.  
  60.  
  61. //------------------------------------------------------------------------------
  62. // Thread
  63. //------------------------------------------------------------------------------
  64. Function jThread_Create(ClassObj : TObject) : jObject;
  65. Const
  66.  _cFuncName = 'jThread_Create';
  67.  _cFuncSig  = '(ILjava/lang/String;)Ljava/lang/Object;';
  68. Var
  69.  Env : PJNIEnv;
  70.  jControls: jobject;
  71.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  72.  _jParams : Array[0..0] of jValue;
  73. begin
  74.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  75.  _jParams[0].l := ClassObj;
  76.  Result := Env^.CallObjectMethodA(Env,jControls,_jMethod,@_jParams);
  77.  Result := Env^.NewGlobalRef(Env,Result);
  78.  dbg(_cFuncName+' 2');
  79. end;
  80.  
  81. Procedure jThread_Free(var Thread : jObject);
  82. Const
  83.  _cFuncName = 'jThread_Free';
  84.  _cFuncSig  = '(Ljava/lang/Object;)V';
  85. Var
  86.  Env : PJNIEnv;
  87.  jControls: jobject;
  88.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  89.  _jParams : Array[0..0] of jValue;
  90. begin
  91.  if Thread = nil then Exit;
  92.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  93.  _jParams[0].l := Thread;
  94.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  95.  Env^.DeleteGlobalRef(Env,Thread);
  96.  Thread := nil;
  97.  dbg(_cFuncName+' 2');
  98. end;
  99.  
  100. Procedure jThread_Run(Thread : jObject);
  101. Const
  102.  _cFuncName = 'jThread_Run';
  103.  _cFuncSig  = '(Ljava/lang/Object;)V';
  104. Var
  105.  Env : PJNIEnv;
  106.  jControls: jobject;
  107.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  108.  _jParams : Array[0..0] of jValue;
  109. begin
  110.  if Thread = nil then Exit;
  111.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  112.  _jParams[0].l := Thread;
  113.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  114.  dbg(_cFuncName+' 2');
  115. end;
  116.  
  117. Procedure jThread_Synchronize(Thread : jObject);
  118. Const
  119.  _cFuncName = 'jThread_Synchronize';
  120.  _cFuncSig  = '(Ljava/lang/Object;)V';
  121. Var
  122.  Env : PJNIEnv;
  123.  jControls: jobject;
  124.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  125.  _jParams : Array[0..0] of jValue;
  126. begin
  127.  if Thread = nil then Exit;
  128.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig,s);
  129.  _jParams[0].l := Thread;
  130.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  131.  dbg(_cFuncName+' 2');
  132. end;
  133.  
  134. Procedure jThread_Resume(Thread : jObject);
  135. Const
  136.  _cFuncName = 'jThread_Resume';
  137.  _cFuncSig  = '(Ljava/lang/Object;)V';
  138. Var
  139.  Env : PJNIEnv;
  140.  jControls: jobject;
  141.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  142.  _jParams : Array[0..0] of jValue;
  143. begin
  144.  if Thread = nil then Exit;
  145.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  146.  _jParams[0].l := Thread;
  147.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  148.  dbg(_cFuncName+' 2');
  149. end;
  150.  
  151. Procedure jThread_Suspend(Thread : jObject);
  152. Const
  153.  _cFuncName = 'jThread_Suspend';
  154.  _cFuncSig  = '(Ljava/lang/Object;)V';
  155. Var
  156.  Env : PJNIEnv;
  157.  jControls: jobject;
  158.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  159.  _jParams : Array[0..0] of jValue;
  160. begin
  161.  if Thread = nil then Exit;
  162.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  163.  _jParams[0].l := Thread;
  164.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  165.  dbg(_cFuncName+' 2');
  166. end;
  167.  
  168. Procedure jThread_Sleep(Thread : jObject; Milliseconds:integer);
  169. Const
  170.  _cFuncName = 'jThread_Sleep';
  171.  _cFuncSig  = '(Ljava/lang/Object;I)V';
  172. Var
  173.  Env : PJNIEnv;
  174.  jControls: jobject;
  175.  _jMethod : jMethodID {$IFDef FPC} = nil {$EndIf};
  176.  _jParams : Array[0..1] of jValue;
  177.  PJ       : Pjvalue;
  178. begin
  179.  if Thread = nil then Exit;
  180.  _jMethod := jGetMethodID(Env,jControls,_cFuncName,_cFuncSig);
  181.  _jParams[0].l := Thread;
  182.  _jParams[1].i := Milliseconds;
  183.  Env^.CallVoidMethodA(Env,jControls,_jMethod,@_jParams);
  184.  dbg(PChar(_cFuncName+' 2 ('+IntToStr(Milliseconds)+')'));
  185. end;
  186.  

Pascal Thread class
Code: Pascal  [Select]
  1. unit osThread;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils,
  7.   And_Controls_Types, jni, And_Controls;
  8.  
  9. { TThread }
  10.  
  11. type
  12.  TThreadMethod = procedure of object;
  13.  TNotifyEvent = procedure(Sender: TObject) of object;
  14.  
  15.  TThread = class
  16.  private
  17.    FHandle: JObject;
  18.    FSuspended: Boolean;
  19.    FFinished: Boolean;
  20.    FRun: Boolean;
  21.    FMethod: TThreadMethod;
  22.  protected
  23.    procedure Execute; virtual; abstract;
  24.    procedure Synchronize(Method: TThreadMethod);
  25.  public
  26.    constructor Create(CreateSuspended: Boolean);
  27.    destructor Destroy; override;
  28.    procedure GenEvent_OnThread(Mode:TThreadMode);
  29.    procedure Sleep(Milliseconds:Longint);
  30.    procedure Resume;
  31.    procedure Suspend;
  32.  end;
  33.  
  34. implementation
  35.  
  36. { TThread }
  37.  
  38. constructor TThread.Create(CreateSuspended: Boolean);
  39. begin
  40.  inherited Create;
  41.  FSuspended:=CreateSuspended;
  42.  FRun := not FSuspended;
  43.  FHandle := jThread_Create(Self,ClassName);
  44.  if FRun then jThread_Run(FHandle);
  45. end;
  46.  
  47. destructor TThread.Destroy;
  48. begin
  49.  if FHandle <> nil then jThread_Free(FHandle);
  50.  FHandle:=nil;
  51.  inherited Destroy;
  52. end;
  53.  
  54. procedure TThread.GenEvent_OnThread(Mode: TThreadMode);
  55. begin
  56.  case Mode of
  57.   Thread_Execute:Execute;
  58.   Thread_Synchronize:if Assigned(FMethod) then FMethod;
  59.  end;
  60. end;
  61.  
  62. procedure TThread.Sleep(Milliseconds: Longint);
  63. begin
  64.  jThread_Sleep(FHandle,Milliseconds);
  65. end;
  66.  
  67. procedure TThread.Resume;
  68. begin
  69.  if not FSuspended then Exit;
  70.  FSuspended := False;
  71.  if not FRun then
  72.  begin
  73.   FRun:=true;
  74.   jThread_Run(FHandle);
  75.   Exit;
  76.  end;
  77.  jThread_Resume(FHandle);
  78. end;
  79.  
  80. procedure TThread.Suspend;
  81. begin
  82.  if FSuspended or not FRun then Exit;
  83.  FSuspended := True;
  84.  if FRun then
  85.  begin
  86.   jThread_Suspend(FHandle);
  87.  end;
  88. end;
  89.  
  90. procedure TThread.Synchronize(Method: TThreadMethod);
  91. begin
  92.  if FSuspended or not FRun then Exit;
  93.  FMethod := Method;
  94.  fInitInfo := InitInfo;
  95.  jThread_Synchronize(FHandle);
  96. end;
  97.  
  98. end.
  99.  

pascal working thread
Code: Pascal  [Select]
  1. unit fuProcessThread;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils,
  7.   And_Controls_Types, jni, And_Controls,
  8.   osThread;
  9.  
  10. type
  11.  
  12. TProcessThread = class(TThread)
  13. private
  14.  fText:String;
  15.  procedure InternalTextSet;
  16. protected
  17.  procedure Execute; override;
  18. public
  19.  
  20. implementation
  21.  
  22. procedure TProcessThread.InternalTextSet;
  23. begin
  24.  .. change the text of the form (SetText)
  25.  .. refresh form (invalidate)
  26.  .. begins a long redraw process (around 10-15 milliseconds)
  27. end;
  28.  
  29. procedure TProcessThread.Execute;
  30. begin
  31.  jdbgf('--------->Execute start');
  32.  ..
  33.  ..
  34.  ..working with a file or something else
  35.  ..
  36.  ..
  37.  ..
  38.  fText:='TEXT';
  39.  Synchronize(@InternalTextSet);
  40.  ..
  41.  ..
  42.  ..continue working with a file or something else
  43.  ..at this point the two threads are run together
  44.  ..
  45.  ..
  46.  ..
  47.  ..here somewhere gives a bug and the program stops
  48.  ..differently once in the main thread elsewhere in the thread
  49.  ..
  50.  .. ----->    an error occurs only when both threads are executed.
  51.  ..
  52.  jdbgf('--------->Execute end');
  53. end;
  54.  
  55. end.
  56.  
« Last Edit: January 22, 2018, 06:52:52 am by tommy_rusev »

tommy_rusev

  • New member
  • *
  • Posts: 5
Re: Android JNI Thread
« Reply #1 on: January 24, 2018, 07:01:21 am »
If I use AsyncTask for a long time, there would be problems with memory leak on onPause, onResume, onConfigurationChanged events ?
Android then destroy and recreate activity and this is problem when using AsyncTask class or I'm mistaken ?

If I use the Service class, I will have the same problems as the Thread class ?

tommy_rusev

  • New member
  • *
  • Posts: 5
Re: Android JNI Thread
« Reply #2 on: January 25, 2018, 08:38:12 pm »
I've solved the problem ...

When the static method Java_Event_pOnThread in Pascal side is called from a second thread and then from the main thread (the second thread does not complete the Java_Event_pOnThread method) has stack problems and JVM terminate the process.

tommy_rusev

  • New member
  • *
  • Posts: 5
Re: Android JNI Thread
« Reply #3 on: January 26, 2018, 05:23:48 pm »
Also add to main unit of application and cthreads unit.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus