3
votes

Play video using youtube player sdk about 30~40 times causes Youtube application crashes, then a DeadObjectException will raise from my app due to the death of remote process. steps to reproduce:

  1. launch activity and initialize YouTubePlayer
  2. load and play a video for a few seconds
  3. release YouTubePlayer and exit activity
  4. repeat step 1-3 about 30~40 times

OutOfMemoryError log(full logs):

08-22 12:01:01.461 E/AndroidRuntime( 3017): FATAL EXCEPTION: main
08-22 12:01:01.461 E/AndroidRuntime( 3017): Process: com.google.android.youtube.player, PID: 3017
08-22 12:01:01.461 E/AndroidRuntime( 3017): java.lang.OutOfMemoryError: Could not allocate JNI Env
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.lang.Thread.nativeCreate(Native Method)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.lang.Thread.start(Thread.java:1063)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:921)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1556)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:310)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:527)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.util.concurrent.ScheduledThreadPoolExecutor.execute(ScheduledThreadPoolExecutor.java:616)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at reo.a(SourceFile:134)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at sgh.a(SourceFile:722)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at gan.a(SourceFile:310)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at gan.b(SourceFile:338)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at com.google.android.apps.youtube.embeddedplayer.service.service.jar.ApiPlayerService$2.run(SourceFile:215)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at android.os.Handler.handleCallback(Handler.java:739)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at android.os.Handler.dispatchMessage(Handler.java:95)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at android.os.Looper.loop(Looper.java:148)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at android.app.ActivityThread.main(ActivityThread.java:5417)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at java.lang.reflect.Method.invoke(Native Method)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
08-22 12:01:01.461 E/AndroidRuntime( 3017):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

and DeadObjectException

08-22 12:01:01.842 E/MonitoringInstrumentation( 2976): java.lang.IllegalStateException: android.os.DeadObjectException
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at gix.surfaceCreated(SourceFile:189)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.SurfaceView.updateWindow(SurfaceView.java:582)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:177)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2055)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.Choreographer.doCallbacks(Choreographer.java:670)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.Choreographer.doFrame(Choreographer.java:606)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.os.Handler.handleCallback(Handler.java:739)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.os.Handler.dispatchMessage(Handler.java:95)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.os.Looper.loop(Looper.java:148)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.app.ActivityThread.main(ActivityThread.java:5417)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at java.lang.reflect.Method.invoke(Native Method)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976): Caused by: android.os.DeadObjectException
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.os.BinderProxy.transactNative(Native Method)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at android.os.BinderProxy.transact(Binder.java:503)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at com.google.android.apps.youtube.embeddedplayer.service.service.jar.ISurfaceHolderService$Stub$Proxy.a(SourceFile:110)
08-22 12:01:01.842 E/MonitoringInstrumentation( 2976):  at gix.surfaceCreated(SourceFile:186)

YouTube App version is 11.29.55 , Nexus 5 emulator with Marshmallow , I've tested it with other versions of YouTube App like 10.25.57 and 10.40.58, the OOM still occurs.

At the very beginning when I encounter this issue I thought it was just caused by some incorrectly api method calls, but after so many hours research I figured out it should be a YouTube App's issue, hope someone can help me to resolve it, or at least avoid it.

The memory of process com.google.android.youtube.player is increasing while player initialization and video playing from Memory Monitor, and many YoutubeService instances created but not recycled from the dump file. Any idea?

I test it with a demo application based on the official YouTubeAndroidAPI sample and the OutOfMemory error occurs as well, I just replaced cueVideo(String) by loadVideo(String) in PlayerViewDemoActivity for auto-playing, and added YouTubePlayer#release() in onDestroy(), also I added a test code based on Espresso to reproduce the memory leak issue.

here is the test code, and here for full demo code.

package com.examples.youtubeapidemo.play;

import android.os.SystemClock;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;

import com.examples.youtubeapidemo.YouTubeAPIDemoActivity;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

/**
 * for YouTubePlayerView testing
 */
@RunWith(AndroidJUnit4.class)
@LargeTest
public class PlayerViewTest {

    @Rule
    public ActivityTestRule<YouTubeAPIDemoActivity> mActivityTestRule =
            new ActivityTestRule<YouTubeAPIDemoActivity>(YouTubeAPIDemoActivity.class);

    @Test
    public void testYouTubeMemoryLeaks() {
        int count = 0;
        while(count < 100) {
            onView(withText("Simple PlayerView")).perform(click());
            SystemClock.sleep(10000); // waiting for video start playing
            pressBack();
            count++;
            Log.i("PlayerViewTest", "count: " + count);
        }
    }
}
1
Did you ever find a fix for this? I'm trying to implement it in my app now and it never releases the instance, causing a huge memory leak.Drew Szurko
@Drew I found a dirty workaround, it works, but I would never encourage anyone to implement it. I noticed com.google.android.youtube process can be killed manually by activityManager.killBackgroundProcesses("com.google.android.youtube");, which requires permission android.permission.KILL_BACKGROUND_PROCESSES and must executed after a youtube player instance released.Liwei Liu
My implementation is kill the process every 10 YouTube Player initialization, it works well and passed my tests, but I still think kill other process manually is definite a bad idea. Also I checked crash statistics from crash stats platform, I found out there're quite few users faced the OOM crash,(1~2 times per week, compares to 50k daily active users, it may related to my app's design, only few users have patient to browser over 30+ vids), then I decided to ignore it.Liwei Liu

1 Answers

0
votes

I reduced the bug occurrence by putting youtube calls (like youtubePlayer.loadVideo(), cueVideo(), getCurrentTimeMillis() etc.) in a try catch block and catch the IllegalStateException exception then reinitialize youtube player.

and worked around it by catching these exceptions and restart activity,

see my answer on this thread : Getting a lot of crashes from android youtube player api