Can't access content provider from espresso test - android

I have an application with more modules. In module A I have a ContentProvider. In module B I am accessing to that ContentProvider. The application works fine I can access the data. My issue is when I am trying to write an android instrumented test for a certain activity. In that activity in the onCreate method I am calling an AsyncTask that needs to access the database via the ContentProvider and populate the activity with that data. In this moment I am getting an error:
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.mycompany.dashboardlight.test, PID: 19196
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:318)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
Caused by: java.lang.SecurityException: Permission Denial: opening provider com.mycompany.data.provider.HibpAccountProvider from ProcessRecord{7e4d57b 19196:com.mycompany.dashboardlight.test/u0a265} (pid=19196, uid=10265) that is not exported from uid 10264
at android.os.Parcel.readException(Parcel.java:1693)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4912)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:6043)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2474)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1521)
at android.content.ContentResolver.query(ContentResolver.java:520)
at android.content.ContentResolver.query(ContentResolver.java:478)
I have tried for both modules to have same shareUserId, seppration of permissions to read and write but nothing works.
This is in the manifest where the content provider is:
<provider
android:name="com.mycompany.data.provider.MyProvider"
android:authorities="${applicationId}.data.MyProvider"
android:enabled="true"
android:exported="false" />
This is the manifest in the module that is accessing the data:
<uses-permission android:name="${applicationId}.data.MyProvider" />
Creating other tests for activities that aren't accessing ContentProvider are working fine.
And this is the test:
#RunWith(AndroidJUnit4.class)
public class MyActivityTest {
#Rule
public final ActivityTestRule<MyActivity> breachMain =
new ActivityTestRule<>(MyActivity.class);
#Test
public void isLaunchScreenDetected() {
onView(withText("No Data Breach Found"))
.check(ViewAssertions.matches(isDisplayed()));
}
}

Finally a solution. The issue was in how it was defined the authority. The applicationId is different for when you are installing the application and when you are trying to test the application. When testing the application you may notice that on your package name is appended .test, and in my case since I used hardcoded value com.mypackage lower in the code this caused the permission denial. So I ended with different authorities, because the applicationId is different when installing the application and running the test.
My proposal if you are defining the AUTHORITY also in your java classes, avoid the ${applicationId} not to have a mix like this.

Related

Android application with camera2 library crash on start for SDK19

I use androidx.camera.camera2 library in my application. This library for SDK 21 and greater. But i want allow users start application for SDK 19 without camera2 support. I check SDK version in my code, but application crash on start. Can i exclude camera2 from dependencies for old SDK?
05-30 12:13:42.318 2000-2000/com.myapp.android E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapp.android, PID: 2000
java.lang.NoClassDefFoundError: android.util.Size
at androidx.camera.camera2.impl.Camera2DeviceSurfaceManager.<clinit>(Camera2DeviceSurfaceManager.java:53)
at androidx.camera.camera2.Camera2AppConfig.create(Camera2AppConfig.java:58)
at androidx.camera.camera2.impl.Camera2Initializer.onCreate(Camera2Initializer.java:44)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1591)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1562)
at android.app.ActivityThread.installProvider(ActivityThread.java:4790)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4385)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4325)
at android.app.ActivityThread.access$1500(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
I recently stumbled into the same issue.
Diving deep into the CameraX code I found that CameraX is initialized in app startup through a content provider. Here is the content provider code where CameraX is being initialized.
public final class Camera2Initializer extends ContentProvider {
private static final String TAG = "Camera2Initializer";
#Override
public boolean onCreate() {
Log.d(TAG, "CameraX initializing with Camera2 ...");
CameraX.init(getContext(), Camera2AppConfig.create(getContext()));
return false;
}
}
Im not very familiar with content providers but my first taught was, this is add at the manifest level? And indeed I was right.
Looking at there manifest I found this
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.camera.camera2">
<application>
<provider
android:name=".Camera2Initializer"
android:authorities="${applicationId}.camerax-init"
android:exported="false"
android:initOrder="100"
android:multiprocess="true" />
</application>
</manifest>
There manifest gets merged into ours which will include this content provider which in the other hand initializes CameraX, we want to avoid this. So one possible way of doing so is creating our own empty content provider and adding it to our manifest with the same name. This will override there content provider.
You can look into
https://developer.android.com/studio/build/manifest-merge
for more detail about manifest merging.
So now with there content provider overriden hopefully you can call
CameraX.init(getContext(), Camera2AppConfig.create(getContext()));
only when the feature gets called and not on app startup.
Im hoping this gets fixed in later versions and allows us to initialize cameraX when we want to.

Different Application class per build variant crashes on some devices

I've modified my build.gradle to use different Application classes based on build-variant (debug / release).
I've added two WrapperApplication classes one in folder "debug", and the second in folder "release", both classes extend some base Application class.
In AndroidManifest I point to com.my.package.WrapperApplication and it indeed uses the correct one.
When releasing a test apk to Play, I got a pre-launch report that my new version crashed on 2 of the 13 devices tested (Moto G and Moto X).
Would love to know why is it crashing, and if something is wrong in the build, how is it working for me and for the other 11 test devices tested.
Here's the stack I received:
FATAL EXCEPTION: main
Process: com.my.package, PID: 16348
java.lang.RuntimeException: Unable to instantiate application com.my.package.WrapperApplication: java.lang.IllegalStateException: Unable to get package info for com.my.package; is package not installed?
at android.app.LoadedApk.makeApplication(LoadedApk.java:516)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4398)
at android.app.ActivityThread.access$1500(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1270)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5102)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: Unable to get package info for com.my.package; is package not installed?
at android.app.LoadedApk.initializeJavaContextClassLoader(LoadedApk.java:376)
at android.app.LoadedApk.getClassLoader(LoadedApk.java:329)
at android.app.LoadedApk.makeApplication(LoadedApk.java:508)
... 11 more
Thanks.
EDIT:
Previously we used the following method, but using the variant-specific folders is cleaner for our build system, so we'd love to switch to it.
Previous method:
AndroidManifest:
<application
android:name="${application}"
... />
build.gradle:
debug {
manifestPlaceholders = [application:".Application1"]
}
release {
manifestPlaceholders = [application: ".Application2"]
}
I don't know what is the reason for the issues. But we are doing a different approach:
We have base Application with common functionality and it also contains protected methods for future behaviour modification:
public class MyApp extends application {
public void onCreate() {
super.onCreate();
initLogging();
}
protected void initLogging() {}
}
We create another app in flavour or build configuration source folder and override behaviour:
public class DebugMyApp extends MyApp {
#Override
protected void initLogging() {
//init Stetho
}
}
We also create another AndroidManifest.xml in flavour or build configuration source folder where we override application name:
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.philips.pins.ugrow"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
​
<application
android:name=".DebugMyApp"
android:label="#string/app_name"
tools:replace="android:name,android:label">
<activity android:name="net.hockeyapp.android.UpdateActivity"/>
</application> ​
</manifest>
Sure extension of the app is not necessary and you can define two different app classes but just correctly define them in manifest files.

SecurityException: Permission Denial: opening provider (fatal exception: asynctask #3)

I am building an Android Library. I kept the code as normal android project while I was developing it and now I converted it into library project (even made a new library project and copied all the code in there just to be sure). The library basically allows user to enter data into database using contentprovider and the library returns that data queried from the database. So whatever app uses the library does not need to use the contentprovider to access data since the library does it all.
I made a very basic app that uses the library, the moment that I make a call to the library the app crashes giving the error code:
FATAL EXCEPTION: AsyncTask #3
Process: com.example.testing, PID: 18991
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.SecurityException: Permission Denial: opening provider thesis.thesis.contentprovider.UsersDataContentProvider from ProcessRecord{42a51b18 18991:com.example.testing/u0a272} (pid=18991, uid=10272) that is not exported from uid 10266
at android.os.Parcel.readException(Parcel.java:1465)
at android.os.Parcel.readException(Parcel.java:1419)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2917)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:4489)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2330)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1441)
at android.content.ContentResolver.query(ContentResolver.java:448)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:65)
at android.content.CursorLoader.loadInBackground(CursorLoader.java:43)
at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69)
at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:57)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
... 3 more
I added permissions to testapp, but didnt change the error
<uses-permission android:name="thesis.thesis.contentprovider.READ_DATABASE" />
<uses-permission android:name="thesis.thesis.contentprovider.WRITE_DATABASE" />
The provider declared in library manifest:
<provider
android:name="thesis.thesis.contentprovider.UsersDataContentProvider"
android:authorities="thesis.thesis.contentprovider"
android:exported="true"
android:readPermission="thesis.thesis.contentprovider.READ_DATABASE"
android:writePermission="thesis.thesis.contentprovider.WRITE_DATABASE" />
At the moment I have exported="true" to see if that was the problem but no. Later I want it to be set false, since the data is sensitive.
Can anyone please direct me to where the problem might be. Also ask if additional information is needed.

The application crashes when using a class inherited from com.activeandroid.app.Application

I use my library Projects ActiveAndroid for which you want to create a class:
import com.activeandroid.app.Application;
public class App extends Application {
#Override
public void onCreate()
{
super.onCreate();
}
}
on the emulator everything works fine, the data stored in the database and so on. but when you start the phone, the application crashes. and immediately.
Error:
01-29 12:55:19.027 14098-14098/com.skip.client.customer E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.skip.client.customer, PID: 14098
java.lang.NoClassDefFoundError: android.support.v4.app.ActivityCompat21$SharedElementCallbackImpl
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:305)
at com.activeandroid.ReflectionUtils.getModelClasses(ReflectionUtils.java:83)
at com.activeandroid.DatabaseHelper.onCreate(DatabaseHelper.java:46)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at com.activeandroid.Registry.openDatabase(Registry.java:149)
at com.activeandroid.Registry.initialize(Registry.java:107)
at com.activeandroid.ActiveAndroid.initialize(ActiveAndroid.java:8)
at com.activeandroid.app.Application.onCreate(Application.java:9)
at com.skip.client.customer.App.onCreate(App.java:12)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4473)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5146)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566)
It looks like getModelClasses() in active android is trying to find a java class in your code that matches the model classes you would have specified in your AndroidManifest.xml. Can you please post your manifest? Specifically, I'm looking for a line like this:
<meta-data
android:name="AA_MODELS"
android:value="
com.example.myapp.Book,
com.example.myapp.Chapter,
com.example.myapp.Library
"/>
If classes Book, Chapter, and Library are not defined in your code, then you'd get the no-class-def-found exception.
Also, I'd recommend changing your app to have your custom app class derive from android.app.Application instead of from the ActiveAndroid app base class. And then explicitly initialize ActiveAndroid. This will allow you to have your own exception handling around ActiveAndroid.initialize() and then explore why your exception is being thrown. You can also use the debugger to step into the initialize() method and see where the exception is coming from.
import com.activeandroid.ActiveAndroid;
public class App extends android.app.Application {
#Override
public void onCreate()
{
super.onCreate();
// add your own exception handling around this. Not that you can do much
// in your app without a database, but at least you'd be able to log a
// meaningful error to the log so you can know details about the exception
// being thrown.
ActiveAndroid.initialize(this);
}
}

java.lang.NoClassDefFoundError on an Activity

I receive a crash report from my production app, which tells me that there is an NoClassDefFound Exception on one of my activity.
The exception is thrown on this line:
final Intent i = new Intent(MainActivity.this, SomeActivity.class);
Where it claims that "SomeActivity" class is not found.
There is only one instance reported out of thousands of users. (On a Samsung Note Mini)
Which means it shouldn't be a compilation or wrong lib included issue.
Is there any clues for me to continue my investigation?
p/s: The activity is definitely defined in manifest. Else it won't even works on other user's phones.
Stack:
java.lang.NoClassDefFoundError: com.sensored.SomeActivity
at com.sensored.MainActivity$2.onItemClicked(MainActivity.java:920)
at com.sensored.adapter.SomeListAdapter$2.onClick(SomeListAdapter.java:115)
at android.view.View.performClick(View.java:2485)
at android.view.View$PerformClick.run(View.java:9080)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3697)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:853)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:611)
at dalvik.system.NativeStart.main(Native Method)
1) Keep all activities under same package[say com.compname.proj.views].
2) Ensure in manifest, package attribute is set to the above package[i.e com.compname.proj.views].
3) In manifest, under all activity tag, make sure android:name attribute has values matching to below pattern:
android:name=".<your activity class name>"
Ex: android:name=".SomeActivity"
My point is not to use package name + activity class name for manifest activity declaration.

Categories

Resources