void MessagePortService::CloseAll(const nsID& aUUID, bool aForced) {
  MessagePortServiceData* data;
  if (!mPorts.Get(aUUID, &data)) {
    MaybeShutdown();
    return;
  }

  if (data->mParent) {
    data->mParent->Close();
  }

  for (const MessagePortServiceData::NextParent& parent : data->mNextParents) {
    parent.mParent->CloseAndDelete();
  }

  nsID destinationUUID = data->mDestinationUUID;

  // If we have informations about the other port and that port has some
  // pending messages to deliver but the parent has not processed them yet,
  // because its entangling request didn't arrive yet), we cannot close this
  // channel.
  MessagePortServiceData* destinationData;
  if (!aForced && mPorts.Get(destinationUUID, &destinationData) &&
      !destinationData->mMessages.IsEmpty() &&
      destinationData->mWaitingForNewParent) {
    MOZ_ASSERT(!destinationData->mNextStepCloseAll);
    destinationData->mNextStepCloseAll = true;
    return;
  }

  mPorts.Remove(aUUID);

  CloseAll(destinationUUID, aForced);

  // CloseAll calls itself recursively and it can happen that it deletes
  // itself. Before continuing we must check if we are still alive.
  if (!gInstance) {
    return;
  }

#ifdef DEBUG
  for (auto iter = mPorts.Iter(); !iter.Done(); iter.Next()) {
    MOZ_ASSERT(!aUUID.Equals(iter.Key()));
  }
#endif

  MaybeShutdown();
}
Exemple #2
0
NS_IMETHODIMP
nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
{
  nsresult rv;

  LOG(("JavaStub::QueryInterface()\n"));
  *aInstancePtr = nsnull;
  nsJavaXPTCStub *master = mMaster ? mMaster : this;

  // This helps us differentiate between the help classes.
  if (aIID.Equals(NS_GET_IID(nsJavaXPTCStub)))
  {
    *aInstancePtr = master;
    NS_ADDREF(this);
    return NS_OK;
  }

  // always return the master stub for nsISupports
  if (aIID.Equals(NS_GET_IID(nsISupports)))
  {
    *aInstancePtr = master->mXPTCStub;
    NS_ADDREF(master);
    return NS_OK;
  }

  // All Java objects support weak references
  if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference)))
  {
    *aInstancePtr = static_cast<nsISupportsWeakReference*>(master);
    NS_ADDREF(master);
    return NS_OK;
  }

  // does any existing stub support the requested IID?
  nsJavaXPTCStub *stub = master->FindStubSupportingIID(aIID);
  if (stub)
  {
    *aInstancePtr = stub->mXPTCStub;
    NS_ADDREF(stub);
    return NS_OK;
  }

  JNIEnv* env = GetJNIEnv();

  // Query Java object
  LOG(("\tCalling Java object queryInterface\n"));
  jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);

  jmethodID qiMID = 0;
  jclass clazz = env->GetObjectClass(javaObject);
  if (clazz) {
    char* sig = "(Ljava/lang/String;)Lorg/mozilla/interfaces/nsISupports;";
    qiMID = env->GetMethodID(clazz, "queryInterface", sig);
    NS_ASSERTION(qiMID, "Failed to get queryInterface method ID");
  }

  if (qiMID == 0) {
    env->ExceptionClear();
    return NS_NOINTERFACE;
  }

  // construct IID string
  jstring iid_jstr = nsnull;
  char* iid_str = aIID.ToString();
  if (iid_str) {
    iid_jstr = env->NewStringUTF(iid_str);
  }
  if (!iid_str || !iid_jstr) {
    env->ExceptionClear();
    return NS_ERROR_OUT_OF_MEMORY;
  }
  PR_Free(iid_str);

  // call queryInterface method
  jobject obj = env->CallObjectMethod(javaObject, qiMID, iid_jstr);
  if (env->ExceptionCheck()) {
    env->ExceptionClear();
    return NS_ERROR_FAILURE;
  }
  if (!obj)
    return NS_NOINTERFACE;

  // Get interface info for new java object
  nsCOMPtr<nsIInterfaceInfoManager>
    iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIInterfaceInfo> iinfo;
  rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo));
  if (NS_FAILED(rv))
    return rv;

  stub = new nsJavaXPTCStub(obj, iinfo, &rv);
  if (!stub)
    return NS_ERROR_OUT_OF_MEMORY;

  if (NS_FAILED(rv)) {
    delete stub;
    return rv;
  }

  // add stub to the master's list of children, so we can preserve
  // symmetry in future QI calls.  the master will delete each child
  // when it is destroyed.  the refcount of each child is bound to
  // the refcount of the master.  this is done to deal with code
  // like this:
  //
  //   nsCOMPtr<nsIBar> bar = ...;
  //   nsIFoo *foo;
  //   {
  //     nsCOMPtr<nsIFoo> temp = do_QueryInterface(bar);
  //     foo = temp;
  //   }
  //   foo->DoStuff();
  //
  // while this code is not valid XPCOM (since it is using |foo|
  // after having called Release on it), such code is unfortunately
  // very common in the mozilla codebase.  the assumption this code
  // is making is that so long as |bar| is alive, it should be valid
  // to access |foo| even if the code doesn't own a strong reference
  // to |foo|!  clearly wrong, but we need to support it anyways.

  stub->mMaster = master;
  master->mChildren.AppendElement(stub);

  *aInstancePtr = stub->mXPTCStub;
  NS_ADDREF(stub);
  return NS_OK;
}