Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   Delphi Android: .SO erstellen und benutzen (https://www.delphipraxis.net/213926-android-so-erstellen-und-benutzen.html)

TurboMagic 20. Okt 2023 12:41

Android: .SO erstellen und benutzen
 
Hallo,

ich versuche gerade eine .SO für Android mit Delphi zu erstellen (10.4.2 oder neuer)
und in einem Testprogramm zu benutzen.

Dazu hab' ich ein Library Projekt erstellt mit einer flachen function drin.
Die hat 2 Integer Parameter und einen Integer Rückgabewert (addiert das einfach nur).

Beim Compilieren wird auch eine .SO Datei erzeugt.
So wie es aussieht kann ich die jedoch nicht statisch einbinden (anders als eine DLL),
weil da der Linker meckert. Also versuche ich das gerade mittels LoadLibrary einzubinden
und ich habe die .SO auch im Deplyoment Manager schon hinzugefügt. Remote-Pfad ist
library\lib\armeabi-v7a\ da ich das bisher mal noch kit 32 Bit zum Testen mache. Funktion
ist cdecl von der Aufruf Konvention.

Nur: zur Laufzeit stürzt die App beim Aufruf einfach ab. Ich prüfe aber den Rückgabewert
von GetProcAddress auf Nil, das kann es also nicht sein.

Logcat hab' ich noch nicht aufgezeichnet, da suche ich noch einen passenden Viewer für, da
ja im Android SDK inzwischen keiner mehr drin ist, ich aber nicht ein komplettes Android
Studio nu für den Viewer installieren möchte...

Code zum Aufruf:

Delphi-Quellcode:
unit GUIMain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Edit, FMX.Controls.Presentation;

type
  TDoAdd = function(a, b: Integer): Integer; cdecl;

  Tf_Main = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    tf_Summand1: TEdit;
    Label3: TLabel;
    l_Result: TLabel;
    tf_Summand2: TEdit;
    b_Calc: TButton;
    procedure b_CalcClick(Sender: TObject);
  private
    FDoAdd : TDoAdd;
  public
  end;

var
  f_Main: Tf_Main;

implementation

uses
  System.IOUtils;

{$R *.fmx}

{$IFDEF WIN32}
function DoAdd(a, b: Integer): Integer; cdecl; external 'SO_Test.dll';
{$ELSE}
//function DoAdd(a, b: Integer): Integer; cdecl; external 'libSO_Test.so';
{$ENDIF}

procedure Tf_Main.b_CalcClick(Sender: TObject);
var
  Handle : HMODULE;
begin
  Handle := LoadLibrary(PChar(TPath.Combine(TPath.GetLibraryPath,
                              'libSO_Test.so')));

  if (Handle <> 0) then
  begin
    try
      FDoAdd := GetProcAddress(Handle, PChar('DoAdd'));

      if (@FDoAdd = nil) then
        l_Result.Text := 'Failure loading proc'
      else
      begin
        l_Result.Text := FDoAdd(tf_Summand1.Text.ToInteger,
                                tf_Summand2.Text.ToInteger).ToString;
        FDoAdd := nil;
      end;
    finally
      FreeLibrary(Handle);
    end;
  end
  else
    l_Result.Text := 'SO handle is invalid'
end;

end.
Hier der relevante Logcat Auszug:

Code:
10-20 13:36:28.234 31445 31445 W adero.SOTestGU: Accessing hidden method Landroid/view/MotionEvent;-><init>()V (greylist-max-o, JNI, denied): com.embarcadero.SOTestGUI
10-20 13:36:28.451  1513  2333 W InputDispatcher: channel 'a66b6a3 PopupWindow:efeb1b3 (server)' ~ Consumer closed input channel or an error occurred. events=0x9: system_server
10-20 13:36:28.451  1513  2333 E InputDispatcher: channel 'a66b6a3 PopupWindow:efeb1b3 (server)' ~ Channel is unrecoverably broken and will be disposed!: system_server
10-20 13:36:28.452  1513  2333 W InputDispatcher: channel '1179c6e com.embarcadero.SOTestGUI/com.embarcadero.firemonkey.FMXNativeActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9: system_server
10-20 13:36:28.452  1513  2333 E InputDispatcher: channel '1179c6e com.embarcadero.SOTestGUI/com.embarcadero.firemonkey.FMXNativeActivity (server)' ~ Channel is unrecoverably broken and will be disposed!: system_server
10-20 13:36:28.463  1513  3607 W InputDispatcher: Attempted to unregister already unregistered input channel 'a66b6a3 PopupWindow:efeb1b3 (server)': system_server
10-20 13:36:28.464  1513  6252 I am_proc_died: [0,31445,com.embarcadero.SOTestGUI,0,2]: system_server
10-20 13:36:28.466   700   700 I Zygote : Process 31445 exited cleanly (231)
10-20 13:36:28.472  1513  2359 W InputDispatcher: Attempted to unregister already unregistered input channel '1179c6e com.embarcadero.SOTestGUI/com.embarcadero.firemonkey.FMXNativeActivity (server)': system_server
10-20 13:36:28.486  1513  6252 I am_uid_stopped: 10310: system_server
10-20 13:36:28.488  1513  6252 I wm_finish_activity: [0,18028204,39,com.embarcadero.SOTestGUI/com.embarcadero.firemonkey.FMXNativeActivity,proc died without state saved]: system_server
10-20 13:36:28.492  1513  6252 I wm_task_removed: [39,removeChild: last r=ActivityRecord{11316ac u0 com.embarcadero.SOTestGUI/com.embarcadero.firemonkey.FMXNativeActivity t-1 f}} in t=Task{f2191ae #39 visible=false type=standard mode=fullscreen translucent=true A=10310:com.embarcadero.SOTestGUI U=0 StackId=39 sz=0}]: system_server
10-20 13:36:28.492  1513  6252 I wm_task_removed: [39,removeTask]: system_server
10-20 13:36:28.492  1513  6252 I wm_task_removed: [39,removeTask]: system_server
10-20 13:36:28.492  1513  6252 I wm_stack_removed: 39: system_server
10-20 13:36:28.496  1513  6252 I wm_set_resumed_activity: [0,com.google.android.packageinstaller/com.android.packageinstaller.DeleteStagedFileOnResult,resumeTopActivityInnerLocked]: system_server
10-20 13:36:28.497  1513  6252 D hmdEnterprise: <isUninstallPackage> blockUninstallpackage =false: system_server
10-20 13:36:28.500  1513  1775 I libprocessgroup: Successfully killed process cgroup uid 10310 pid 31445 in 36ms: system_server
Wer hat noch eine Idee?
Die nächsten Versuche werde ich mit StdCall Aufrufkonvention und von 11.3 aus durchführen.
Evtl. noch die .SO in einen anderen Pfad bereitstellen lassen? .\internal\assets vielleicht?

paule32.jk 20. Okt 2023 13:50

AW: Android: .SO erstellen und benutzen
 
Hallo,

LoadLibrary, und WM_(Nachrichten) sind Windows spezifiesch und können nicht in ein Android Project verwendet werden.
Du must Funktionen und Konstanten verwenden, die für Android unterstützt werden

TurboMagic 20. Okt 2023 14:01

AW: Android: .SO erstellen und benutzen
 
Hallo,

deine Antwort mit LoadLibrary ist leider falsch!
Wenn du dir mal System.SysUtils.pas anschaust, wirst du sehen, dass es dort
sowohl ein LoadLibrary für Posix Plattformen gibt!

Das ruft intern dlopen auf!

Und von Windows Botschaftsn hab' ich gar nix geschrieben (ja, war von dir nur ein Beispiel).

Grüße
TurboMagic

TurboMagic 20. Okt 2023 14:04

AW: Android: .SO erstellen und benutzen
 
Eine neue Erkenntnis (diesmal von D11.3):
Gebe ich mit TPath.GetLibraryPath in einen String aus:

s := TPath.Combine(TPath.GetLibraryPath, 'libSO_Test.so');

Erhalte ich das:
'/data/app/~~td-k7J_qLsGigGgnn9hKrw==/com.embarcadero.SOTestGUI-mFk3eeCSAweRM71VBK_lvw==/lib/arm/libSO_Test.so'

Ich weiß aber nicht ob das korrekt ist und es sieht auch nicht unbeding so aus als würde es zum Remote Pfad
library\lib\armeabi-v7a\ passen...

Wie müsste ich den Remote Pfad ändern?
Einfach in lib/arm/ ist wohl nicht richtig, da ich dann später beim Hinzufügen der 64 Bit .SO ein Problem bekomme...

Grüße
TurboMagic

paule32.jk 20. Okt 2023 14:31

AW: Android: .SO erstellen und benutzen
 
mein altes SAMSUNG Android Galaxy hat die Möglichkeit, die Verzeichnis-Struktur anzeigen
zu lassen.

TurboMagic 20. Okt 2023 14:37

AW: Android: .SO erstellen und benutzen
 
Hallo,

danke für den Tipp.
Leider war ich da auch schon ;-)
Nur ist das bei den neueren Geräte meist schreibgeschützt und nicht mal die
Shell (adb shell) kann da überall rein bzw. zeigt Unterordner an.

Aber: glücklicherweise gibt's ja System.SysUtils.FileExists und das sagt, dass
es die betreffende .SO an dem Pfad wirklich gibt.

Tja, nur warum crasht das dann beim LoadLibrary? :-(

Grüße
TurboMagic

paule32.jk 20. Okt 2023 15:58

AW: Android: .SO erstellen und benutzen
 
könnte an die Rechte liegen - oder das falsche binär Format.
Mit den GNU C/C++ kannst Du für beliebige Systeme .EXE, .DLL, .SO schreiben.
Allerdings hat jede Architektur und Chip ein Eigenes Format.

z.B. ist es ein Unterschied, wenn man versucht ein 64 Bit Image auf einer 32 Bit Umgebung zu starten - das geht in der Regel nicht.
Anders als auf einen 64 Bit System, dort können 32 Images gestartet werden.

Dann liegst auch an den Endian / BigEndian.

Oder Du hast Funktionen, die es in dem Image nicht gibt.

Unter Windows in der MSYS2 Shell gibt es wie unter Linux ein Tool namens "ldd" - nicht an den "ld" Linker denken !

LDD prüft, welche Bibliotheken verwendet werden, und zeigt deren "einkompilierten" Pfade an.
Wenn der Pfad nicht existiert, dann wird die Lade-Adresse 0 sein, und führt daher zu einen Lade-Fehler.

himitsu 20. Okt 2023 16:13

AW: Android: .SO erstellen und benutzen
 
Zitat:

Zitat von paule32.jk (Beitrag 1528460)
Anders als auf einen 64 Bit System, dort können 32 Images gestartet werden.

jaaa-nein

So wie im 64 Bit-Windows das 16 Bit-Subsystem entfernt wurde, weswegen man dort keine 16 Bit-DOS-Programme (*.com) mehr starten kann,
kann man auch das 32 Bit SubSystem entfernen. (keine 32 Bit-DLLs und Programme des Windows installieren)
-> dann könnte man zwar in der CPU noch 32 Bit-Code ausführen, aber wenn die 32 Bit-WinAPI fehlt, läuft dennoch fast nichts.

Auch muß man in eine 64 Bit-CPU keine 32 Bit-Instruktionen einbauen (oder das OS verietet das Umschalten),
womit dann garnichts mehr mit 32 Bit ginge.


PS: Das Gegenteil davon macht Wine ... es stellt quasi einen Großteil der Win32-API bereit (vorwiegend als Umleitung auf die Linux-API/Funktionen), wordurch Windows-Programme dort laufen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz