How does Surface handle garbage collection after parsing on Android?

Im using the source code forSurface.java as a reference for this question.

The surface implements the Parcelable interface and also contains an object handle on the inside.

I am interested to know how garbage collection is handled in this case:

  • Surface (A) is created and recorded in the Package. After that, there are no links to it.

  • A copy of the original surface (B) is read from the Parcel; let's say this happens in another thread used for rendering. This instance now contains the same native descriptor as (A), and theres a strong reference to this instance somewhere.

  • It turns out GC, and (A) is collected, since it is no longer referenced. Running finalize(), which calls release(), which, in turn, calls the nativeRelease(long)built-in descriptor.

A quick glance at the source code made me think that now (B) should also throw out the bucket and stop working, since its own descriptor is called, but after trying to replicate, this does not seem to be the case. (A) is collected, but (B) lives and remains usable.

Now I get the feeling that some sites are counting links to their own object or some other magic on the side of the forwarding process.

, , Im , , . Im , Surface lock .

+4
1

- BufferQueue. Binder, . JNI:

static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) {
  Parcel* parcel = parcelForJavaObject(env, parcelObj);
  if (parcel == NULL) {
    doThrowNPE(env);
    return 0;
  }

  android::view::Surface surfaceShim;

  // Calling code in Surface.java has already read the name of the Surface
  // from the Parcel
  surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);

  sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));

  // update the Surface only if the underlying IGraphicBufferProducer
  // has changed.
  if (self != nullptr
        && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
                IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
      // same IGraphicBufferProducer, return ourselves
      return jlong(self.get());
  }

  sp<Surface> sur;
  if (surfaceShim.graphicBufferProducer != nullptr) {
    // we have a new IGraphicBufferProducer, create a new Surface for it
    sur = new Surface(surfaceShim.graphicBufferProducer, true);
    // and keep a reference before passing to java
    sur->incStrong(&sRefBaseOwner);
  }

  if (self != NULL) {
    // and loose the java reference to ourselves
    self->decStrong(&sRefBaseOwner);
  }

  return jlong(sur.get());
}

, Binder Parcel IGraphicBufferProducer IPC.

, , , .

, , native Surface :

sp<Surface> Surface::readFromParcel(const Parcel& data) {
  Mutex::Autolock _l(sCachedSurfacesLock);
  sp<IBinder> binder(data.readStrongBinder());
  sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote();
  if (surface == 0) {
   surface = new Surface(data, binder);
   sCachedSurfaces.add(binder, surface);
  } else {
    // The Surface was found in the cache, but we still should clear any
    // remaining data from the parcel.
    data.readStrongBinder();  // ISurfaceTexture
    data.readInt32();         // identity
  }
  if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
    surface = 0;
  }
  cleanCachedSurfacesLocked();
  return surface;
}

Java Surface, parcelling/unparcelling , Surface, , - : .

, IGraphicBufferProducer contract :

// connect attempts to connect a client API to the IGraphicBufferProducer.
// This must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator.
//
// This method will fail if the connect was previously called on the
// IGraphicBufferProducer and no corresponding disconnect call was made.
//
// outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers,
// respectively. The token needs to be any binder object that lives in the
// producer process -- it is solely used for obtaining a death notification
// when the producer is killed.
virtual status_t connect(const sp<IBinder>& token,
        int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;

- Android .

+7

Source: https://habr.com/ru/post/1659133/


All Articles