QuinnF
QuinnF

Reputation: 2209

Android Camera2 API SecurityException

I'm trying to use the new Android camera2 api. I started with source from this tutorial : http://jylee-world.blogspot.com/2014/12/a-tutorial-of-androidhardwarecamera2.html . When I try to usb-debug-deploy it to any phone, I get a SecurityException from CameraManager.openCamera(...).

My AndroidManifest looks like this:

<uses-feature android:name="com.android.hardware.camera2.full"/>
<uses-permission android:name="android.permission.CAMERA"/>

This seems to be what every tutorial I've been able to find does. I'm able to get permission for other actions; for example, I can make the camera vibrate just fine. I'm also able to enumerate cameras with CameraManager.getCameraIdLists() just fine, but I'm not sure if that actually requires permission. But I can't openCamera.

Are there some additional permissions I need? Am I doing something wrong?

Thanks for the help!

This is my full stack trace:

SecurityException
java.lang.SecurityException: Lacking privileges to access camera serviceat android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108)
        at android.hardware.camera2.legacy.CameraDeviceUserShim.connectBinderShim(CameraDeviceUserShim.java:336)
        at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:327)
        at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:457)
        at com.example.quinnfreedman.camera2test.MainActivity$1.onSurfaceTextureAvailable(MainActivity.java:74)
        at android.view.TextureView.getHardwareLayer(TextureView.java:368)
        at android.view.View.updateDisplayListIfDirty(View.java:15167)
        at android.view.View.draw(View.java:15964)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3612)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3402)
        at android.view.View.updateDisplayListIfDirty(View.java:15185)
        at android.view.View.draw(View.java:15964)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3612)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3402)
        at android.view.View.updateDisplayListIfDirty(View.java:15185)
        at android.view.View.draw(View.java:15964)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3612)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3402)
        at android.view.View.updateDisplayListIfDirty(View.java:15185)
        at android.view.View.draw(View.java:15964)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3612)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3402)
        at android.view.View.draw(View.java:16197)
        at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2690)
        at android.view.View.updateDisplayListIfDirty(View.java:15190)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:281)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:287)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:322)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2627)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2446)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2079)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1119)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6060)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
        at android.view.Choreographer.doCallbacks(Choreographer.java:670)
        at android.view.Choreographer.doFrame(Choreographer.java:606)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
        at android.os.Handler.handleCallback(Handler.java:746)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5443)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

Upvotes: 0

Views: 6094

Answers (4)

Brian
Brian

Reputation: 3713

Struggled with this off and on for weeks, thinking several times I'd solved the problem. In the end, none of the "fixes" I'd read about here worked. Then, after putting in ~100 Log.v statements in my Java, I realized it was a threading issue that might, or might not, kick off this error depending on events on the camera. Basically, I think, the main program was running on the main thread, but there was an extra thread kicked off by the following statement:

//this code seems to be the culprit  ... commenting it out solve my problem
private void showToast(final String text) {
    final Activity activity = MyStupidProgram.this;
    if (activity != null) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

So while there's nothing in this statement calling the camera, perhaps because of thread safety, Android 5.x and 6.x were throwing security errors when I called showToast('some crap');

Commenting that out and just using a Toast.makeText('blah blah'); statement, I was able to get rid of the security error.

Additionally, I added this to the code on the page's onCreate(); statement, to catch any issues on the main thread:

    Thread.setDefaultUncaughtExceptionHandler(
            new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(
                        Thread paramThread,
                        Throwable paramThrowable
                ) {
                    //Do your own error handling here

                    if (exceptionHandler != null)
                        exceptionHandler.uncaughtException(
                                paramThread,
                                paramThrowable
                        ); //Delegates to Android's error handling
                    else
                        System.exit(2); //Prevents the service/app from freezing
                }
            });

Upvotes: 0

User
User

Reputation: 101

Just close your camera device in onSurfaceTextureDestroyed function

 onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture){cameraDevice.close();cameraDevice = null;}

Security exception will get fix

Upvotes: 1

Umesh Singh Kushwaha
Umesh Singh Kushwaha

Reputation: 5741

In Android M, run time permission check is required for dangerous permission. You can see dangerous permission here.

Check for permission :

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.CAMERA);

If the app has the permission, the method returns PackageManager.PERMISSION_GRANTED, and the app can proceed with the operation. If the app does not have the permission, the method returns PERMISSION_DENIED, and the app has to explicitly ask the user for permission.

For details: https://developer.android.com/training/permissions/requesting.html#perm-request

Upvotes: 4

Lucas Ferraz
Lucas Ferraz

Reputation: 4152

When you are running your application on android 6+, you need to give the famous runtime permissions. https://developer.android.com/training/permissions/requesting.html

The permission you are trying to give is considered a dangerous permissions android. https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous

Different of other responses about runtime permission, I suggest you to use this https://github.com/Karumi/Dexter

This lib makes the permission handling easily

Upvotes: 0

Related Questions