MediaRecorder.getSurface() terminates foreground service

Viewed 71

I am trying to get screen recording work from a foreground service, with media recorder calling this method:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startRecording(int resultCode, Intent data) {
    Log.v(TAG, "Starting recording...");

    MediaProjectionManager mProjectionManager = (MediaProjectionManager) getApplicationContext().getSystemService (Context.MEDIA_PROJECTION_SERVICE);
    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setOnErrorListener(this::onRecorderError);
    mMediaRecorder.setOnInfoListener(this::onRecorderInfo);

    DisplayMetrics metrics = new DisplayMetrics();
    WindowManager wm = (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE);
    wm.getDefaultDisplay().getRealMetrics(metrics);

    int mScreenDensity = metrics.densityDpi;
    int displayWidth = metrics.widthPixels;
    int displayHeight = metrics.heightPixels;

    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mMediaRecorder.setVideoEncodingBitRate(8 * 1000 * 1000);
    mMediaRecorder.setVideoFrameRate(15);
    mMediaRecorder.setVideoSize(displayWidth, displayHeight);

    Log.v(TAG, "Recorder parameters done");

    String videoDir = Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES).getAbsolutePath();
    Long timestamp = System.currentTimeMillis();

    String orientation = "portrait";
    if( displayWidth > displayHeight ) {
        orientation = "landscape";
    }
    String filePathAndName = videoDir + "/time_" + timestamp.toString() + "_mode_" + orientation + ".mp4";

    mMediaRecorder.setOutputFile( filePathAndName );

    Log.v(TAG, "Recorder output path done, prepairing...");

    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    Log.v(TAG, "Recorder prepaired");
    Surface surface = mMediaRecorder.getSurface(); //Stops here
    Log.v(TAG, "Surface ready");
    mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    Log.v(TAG, "Media projection ready");
    mVirtualDisplay = mMediaProjection.createVirtualDisplay("MainActivity",
            displayWidth, displayHeight, mScreenDensity, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            surface, null, null);
    Log.v(TAG, "Display ready");
    mMediaRecorder.start();

    Log.v(TAG, "Started recording");
}

But when i call mMediaRecorder.getSurface(), activity just stops completly, no exceptions, no callbacks from mMediaRecorder, not even calling onDestory() of my service, but the app itself keeps running

It is as if service just stops working at all

What am i doing wrong? I am testing on android 9.1.0.181C10 HUAWEI LLD-L31

2 Answers

Not exact one but I might have seen similar problem while investigating the cause of strange crashes around MediaCodec, which occurred only on some Huawei, Samsung and Motorola devices.

Long story short, it was due to laziness. It takes time for MediaCodec to get ready on those devices. Trying to let it run too quickly, underlying system module falls into infinite loop and gets terminated forcibly.

If you could find LogCat exhausting some lines containing "libstagefright_foundation.so" or "__ubsan_handle_mul_overflow_minimal_abort", that would be. Then, try inserting a little delay e.g. Thread.sleep(100) after the MediaRecorder.prepare() for workaround.

Turns out problem was in app permissions. Since i was deleting and installing it several times, app permissions were reset, and application lost its file access permission. When i enabled it in settings, it worked as intended

Related