gluonhq / attach

GNU General Public License v3.0
49 stars 26 forks source link

StorageService crashes app #343

Closed chrishpowell closed 1 year ago

chrishpowell commented 1 year ago

Gluon StorageService in Android app crashes. Code (GluonApplication2) is simply:

:
public void init() {
        File externDir = null;

        Optional<StorageService> ss = StorageService.create();
        if( ss.isPresent() ) {
            StorageService strge = ss.get();

            // External storage
            if( !strge.isExternalStorageReadable() )  // *** Seems to cause the crash
                { System.out.println("ERR: External storage is not readable!"); }
        }
        :
 }

The app starts, the expected popup appears (to grant permission) which, when allowed, causes the app to minimise. Subsequent runs simply stop and multiple runs throw up on screen: "GluonApplication2 keeps stopping".

Using the following Gluon/Graal config: graalvm-svm-java17-linux-gluon-22.1.0.1-Final, javafx 17.0.2, Attach 4.0.16, Glisten 6.2.2, Android 12 the following Nativerun/logcat crash log occurs:

:
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475): FATAL EXCEPTION: main
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475): Process: com.gluonapplication2.gluonapplication2, PID: 21475
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475): java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Looper android.app.Activity.getMainLooper()' on a null object reference
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at com.gluonhq.helloandroid.Util$1.run(Util.java:90)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at android.os.Handler.handleCallback(Handler.java:938)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at android.os.Handler.dispatchMessage(Handler.java:99)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at android.os.Looper.loopOnce(Looper.java:226)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at android.os.Looper.loop(Looper.java:313)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at android.app.ActivityThread.main(ActivityThread.java:8751)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at java.lang.reflect.Method.invoke(Native Method)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] E/AndroidRuntime(21475):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
[Sun Nov 13 09:41:25 EET 2022][INFO] [SUB] W/ActivityManager(  959): crash : com.gluonapplication2.gluonapplication2,10513
:

I tried the 4.0.16-SNAPSHOT as well with the same results. 4.0.17-SNAPSHOT appears to be lacking the StorageService, so I could not use that either. 4.0.15 does not work on Android 12 (see https://stackoverflow.com/questions/73907691/gluon-google-play-android-target-api-fails). An early version of the 4.0.16-SNAPSHOT worked. I tried this also with the GluonFX 1.0.16-SNAPSHOT but that made no difference. I should add that my AndroidManifest.xml has the relevant permissions:

<?xml version='1.0'?>
<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.gluonapplication2.gluonapplication2' android:versionCode='1' android:versionName='1'>
    <supports-screens android:xlargeScreens="true"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <application android:label='GluonApp' android:icon="@mipmap/ic_launcher">
        <activity android:name='com.gluonhq.helloandroid.MainActivity' android:configChanges="orientation|keyboardHidden">
             <intent-filter>
                <category android:name='android.intent.category.LAUNCHER'/>
                <action android:name='android.intent.action.MAIN'/>
             </intent-filter>
        </activity>
        <activity android:name="com.gluonhq.impl.charm.down.plugins.android.PermissionRequestActivity" />
        <activity android:name='com.gluonhq.helloandroid.PermissionRequestActivity'/>
    </application>
</manifest>

I have tested PrivateStorage and that works.

jperedadnr commented 1 year ago

Storage is available, like the rest of the services, in 4.0.17-SNAPSHOT: https://oss.sonatype.org/content/repositories/snapshots/com/gluonhq/attach/storage/4.0.17-SNAPSHOT/

In any case, 4.0.16 has a fix for the clipboard that affects Utils in the line 90 that shows on your stack trace.

Does this only happen on Android 12, have you test other versions? Can you upload an apk?

GluonFX plugin 1.0.16 has just been released, btw.

And why is there charm.down.plugins in your manifest?

<activity android:name="com.gluonhq.impl.charm.down.plugins.android.PermissionRequestActivity" />
chrishpowell commented 1 year ago

Apologies, with 4.0.17, I'd forgotten to clean the project. The charm PermissionRequestActivity is because I simply copied the AndroidManifest from another project.

I have now re-tested with 4.0.17-SNAPSHOT and I still get the crash. I have only tested against Android 12 as this is my main focus at the moment. To test, I simply took the IDE Single View generated project and added a few lines for StorageService into the main line (here called GluonSimple). BasicView (with "Hello JavaFX World!") code was not altered.

For completeness, the GluonSimple code is:

package com.gluonsimple;

import com.gluonhq.charm.glisten.application.AppManager;
import com.gluonhq.charm.glisten.visual.Swatch;
import com.gluonhq.attach.storage.StorageService;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.util.Optional;

import static com.gluonhq.charm.glisten.application.AppManager.HOME_VIEW;

public class GluonSimple extends Application {

    private final AppManager appManager = AppManager.initialize(this::postInit);

    @Override
    public void init() {
        // Add StorageService to generated Gluon Single View project
        Optional<StorageService> ss = StorageService.create();
        if( ss.isPresent() ) {
            StorageService strge = ss.get();

            // External storage
            if( !strge.isExternalStorageReadable() )
                { System.out.println("ERR: External storage is not readable!"); }
        }

        appManager.addViewFactory(HOME_VIEW, BasicView::new);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        appManager.start(primaryStage);
    }

    private void postInit(Scene scene) {
        Swatch.BLUE.assignTo(scene);

        ((Stage) scene.getWindow()).getIcons().add(new Image(GluonSimple.class.getResourceAsStream("/icon.png")));
    }

    public static void main(String args[]) {
        launch(args);
    }
}

The pom is:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.gluonsimple</groupId>
    <artifactId>gluonsimple</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>GluonSimple</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <graalvm.home>/home/chrispowell/java/graalvm-svm-java17-linux-gluon-22.1.0.1-Final/</graalvm.home>
        <maven.compiler.release>11</maven.compiler.release>
        <javafx.version>17.0.2</javafx.version>
        <attach.version>4.0.17-SNAPSHOT</attach.version>
        <gluonfx.plugin.version>1.0.16</gluonfx.plugin.version>
        <javafx.plugin.version>0.0.8</javafx.plugin.version>
        <mainClassName>com.gluonsimple.GluonSimple</mainClassName>
        <app.description>GluonSimple</app.description>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq</groupId>
            <artifactId>charm-glisten</artifactId>
            <version>6.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq.attach</groupId>
            <artifactId>display</artifactId>
            <version>${attach.version}</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq.attach</groupId>
            <artifactId>lifecycle</artifactId>
            <version>${attach.version}</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq.attach</groupId>
            <artifactId>statusbar</artifactId>
            <version>${attach.version}</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq.attach</groupId>
            <artifactId>storage</artifactId>
            <version>${attach.version}</version>
        </dependency>
        <dependency>
            <groupId>com.gluonhq.attach</groupId>
            <artifactId>util</artifactId>
            <version>${attach.version}</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>Gluon</id>
            <url>https://nexus.gluonhq.com/nexus/content/repositories/releases</url>
        </repository>
        <repository>
            <id>Gluon2</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>Gluon</id>
            <name>Sonatype</name>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>

            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>${javafx.plugin.version}</version>
                <configuration>
                    <mainClass>${mainClassName}</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <!-- Default configuration for running -->
                        <!-- Usage: mvn clean javafx:run -->
                        <id>default-cli</id>
                    </execution>
                    <execution>
                        <!-- Configuration for manual attach debugging -->
                        <!-- Usage: mvn clean javafx:run@debug -->
                        <id>debug</id>
                        <configuration>
                            <options>
                                <option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000</option>
                            </options>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- Configuration for automatic IDE debugging -->
                        <id>ide-debug</id>
                        <configuration>
                            <options>
                                <option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
                            </options>
                        </configuration>
                    </execution>
                    <execution>
                        <!-- Configuration for automatic IDE profiling -->
                        <id>ide-profile</id>
                        <configuration>
                            <options>
                                <option>${profiler.jvmargs.arg1}</option>
                                <option>${profiler.jvmargs.arg2}</option>
                                <option>${profiler.jvmargs.arg3}</option>
                                <option>${profiler.jvmargs.arg4}</option>
                                <option>${profiler.jvmargs.arg5}</option>
                            </options>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>com.gluonhq</groupId>
                <artifactId>gluonfx-maven-plugin</artifactId>
                <version>${gluonfx.plugin.version}</version>
                <configuration>
                    <target>${gluonfx.target}</target>
                    <attachList>
                        <list>display</list>
                        <list>lifecycle</list>
                        <list>statusbar</list>
                        <list>storage</list>
                    </attachList>
                    <verbose>true</verbose>
                    <mainClass>${mainClassName}</mainClass>
                    <graalvmHome>${graalvm.home}</graalvmHome>
                    <releaseConfiguration>
                        <!-- all targets -->
                        <packageType></packageType>
                        <description>${app.description}</description>
                        <vendor>discoveri</vendor>
                        <!-- macOS -->
                        <macAppStore></macAppStore>
                        <macSigningUserName></macSigningUserName>
                        <macAppCategory></macAppCategory>
                        <!-- macOS/iOS -->
                        <bundleName></bundleName>
                        <bundleVersion>1.0</bundleVersion>
                        <bundleShortVersion>1.0</bundleShortVersion>
                        <providedSigningIdentity></providedSigningIdentity>
                        <providedProvisioningProfile></providedProvisioningProfile>
                        <skipSigning>false</skipSigning>
                        <!-- iOS Simulator -->
                        <simulatorDevice></simulatorDevice>
                        <!-- Android -->
                        <appLabel>${app.description}</appLabel>
                        <versionCode>1</versionCode>
                        <versionName>1</versionName>
                    </releaseConfiguration>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>ios</id>
            <properties>
                <gluonfx.target>ios</gluonfx.target>
            </properties>
        </profile>
        <profile>
            <id>android</id>
            <properties>
                <gluonfx.target>android</gluonfx.target>
            </properties>
        </profile>
    </profiles>
</project>

The AndroidManifest is:

<?xml version='1.0'?>
<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.gluonsimple.gluonsimple' android:versionCode='1' android:versionName='1'>
    <supports-screens android:xlargeScreens="true"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- Permissions: -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application android:label='GluonSimple' android:icon="@mipmap/ic_launcher">
        <activity android:name='com.gluonhq.helloandroid.MainActivity'
                  android:exported="true"
                  android:configChanges="orientation|keyboardHidden">
             <intent-filter>
                <category android:name='android.intent.category.LAUNCHER'/>
                <action android:name='android.intent.action.MAIN'/>
             </intent-filter>
        </activity>
        <activity android:name='com.gluonhq.helloandroid.PermissionRequestActivity' android:exported="true"/>
    </application>
</manifest>

I could upload the 4.0.16 and/or the 4.0.17 apk versions but they are 28Mb each. Let me know if you'd like to me to do so.

I am not sure how I would implement the fix you mention. Should this not already be in 4.0.17-SNAPSHOT?

jperedadnr commented 1 year ago

I meant that there is already a fix in place since Attach 4.0.16, that was done specifically for the Android clipboard.

It is likely that this fix is causing the issues with storage on Android 12, but I'd like to test on Android 11 or 10 as well. If you could upload a zip with your apk that would be great. If it is too big, upload it to Google Drive or so and post a link to it?

chrishpowell commented 1 year ago

I have uploaded is the 4.0.17-SNAPSHOT apk GluonSimple here: https://drive.google.com/file/d/1V4RFnV_AgVX-L18g6SyvtDc87czAVCTl/view?usp=sharing

jperedadnr commented 1 year ago

The app worked fine for me (Pixel XL, Android 10) the first time I installed, but then I uninstalled and installed again, and I get the crash:

11-17 11:40:12.794  7791  7819 D GluonAttach: Calling Verify Permissions from Attach::Util
11-17 11:40:12.795  7791  7819 V GraalActivity: PermissionRequestActivity::Calling verifyPermissions
11-17 11:40:12.797  7791  7819 V GraalActivity: Permission android.permission.READ_EXTERNAL_STORAGE is not granted
11-17 11:40:12.799  7791  7819 V GraalActivity: PermissionRequestActivity::start intent to requestPermission
11-17 11:40:12.801   929  2879 I ActivityTaskManager: START u0 {flg=0x10000000 cmp=com.gluonsimple.gluonsimple/com.gluonhq.helloandroid.PermissionRequestActivity (has extras)} from uid 10212
11-17 11:40:12.804   671   671 D QCOM PowerHAL: LAUNCH HINT: ON
11-17 11:40:12.818   929  1069 I ActivityTaskManager: Displayed com.gluonsimple.gluonsimple/com.gluonhq.helloandroid.PermissionRequestActivity: +446ms
11-17 11:40:12.823  7791  7791 D AndroidRuntime: Shutting down VM
--------- beginning of crash
11-17 11:40:12.824  7791  7791 E AndroidRuntime: FATAL EXCEPTION: main
11-17 11:40:12.824  7791  7791 E AndroidRuntime: Process: com.gluonsimple.gluonsimple, PID: 7791
11-17 11:40:12.824  7791  7791 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Looper android.app.Activity.getMainLooper()' on a null object reference
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at com.gluonhq.helloandroid.Util$1.run(Util.java:90)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:883)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:100)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:214)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:7356)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
11-17 11:40:12.824  7791  7791 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Will look into it.

jperedadnr commented 1 year ago

@chrishpowell It should be fixed now with 4.0.17-SNAPSHOT, can you test?

chrishpowell commented 1 year ago

Excellent! Tried with a couple of apps, all seems to work well.

Btw, I have been seeing this appearing when building/packaging:

[Fri Nov 18 12:58:12 EET 2022][FINE] [SUB] Setting the namespace via a source AndroidManifest.xml's package attribute is deprecated.
[Fri Nov 18 12:58:12 EET 2022][FINE] [SUB] Please instead set the namespace (or testNamespace) in the module's build.gradle file, as described here: https://developer.android.com/studio/build/configure-app-module#set-namespace

Will there be a namespace tag in the releaseConfiguration of the POM or some other simple way of namespacing? Or do we twiddle with the gradle build config somehow?

jperedadnr commented 1 year ago

Great.

Can you file an issue for that here? The default AndroidManifest needs to change and move the package name to the build.gradle file.