Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Crash in test environment in Slow test card mode.

Discussion in 'Unity IAP' started by k_belonogov, Mar 29, 2021.

  1. k_belonogov

    k_belonogov

    Joined:
    Jan 12, 2016
    Posts:
    10
    Unity 2020.17.f1
    Unity IAP 3.0.1

    In any cases Approves or Declines after a few minutes.
    The reproduce is not stable.
    Steps:
    - Buy something in test environment in mode Approves after a few minutes.
    - Turn off screen
    - Wait for 5 minutes
    - Wake up the device
    - Crash

    UnityEngine.Purchasing.GooglePurchaseUpdatedListener.OnPurchaseOk:UnityEngine.AndroidJavaProxy.Invoke: Object reference not set to an instance of an object.

    Stacktrace:
    at UnityEngine.Purchasing.GooglePurchaseUpdatedListener.OnPurchaseOk (UnityEngine.Purchasing.Models.GooglePurchase googlePurchase)
    at System.Action`1[T].Invoke (T obj)
    at UnityEngine.Purchasing.GooglePurchaseUpdatedListener.ApplyOnPurchases (UnityEngine.AndroidJavaObject purchasesList, System.Action`1[T] action)
     
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  3. k_belonogov

    k_belonogov

    Joined:
    Jan 12, 2016
    Posts:
    10
    As I have already mentioned, unfortunately, this crash is unstable. 1 / 10 crashing.
    For playground cases is not critical. But when you have online about 10k concurrent users...

    I've investigated the code
    Code (CSharp):
    1.  
    2. void ApplyOnPurchases(AndroidJavaObject purchasesList, Action<GooglePurchase> action)
    3.         {
    4.             int size = purchasesList.Call<int>("size");
    5.             for (int index = 0; index < size; index++)
    6.             {
    7.                 AndroidJavaObject purchase = purchasesList.Call<AndroidJavaObject>("get", index);
    8.                 GooglePurchase googlePurchase = GooglePurchaseHelper.MakeGooglePurchase(m_GoogleCachedQuerySkuDetailsService.GetCachedQueriedSkus().ToList(), purchase);
    9.                 action(googlePurchase);
    10.             }
    11.         }
    12.  
    This helper
    Code (CSharp):
    1.  
    2. GooglePurchaseHelper.MakeGooglePurchase
    3.  
    can return null in some cases.

    Code (CSharp):
    1.  
    2. internal static GooglePurchase MakeGooglePurchase(IEnumerable<AndroidJavaObject> skuDetails, AndroidJavaObject purchase)
    3. {
    4.     ...
    5.     return skuDetail != null ? new GooglePurchase(purchase, skuDetail) : null;
    6. }
    7.  
    And then this null result can propagate into
    Code (CSharp):
    1.  
    2. void OnPurchaseOk(GooglePurchase googlePurchase)
    3. {
    4.     if (googlePurchase.purchaseState == GooglePurchaseStateEnum.Purchased())
    5.     {
    6.         m_GooglePurchaseCallback.OnPurchaseSuccessful(googlePurchase.sku, googlePurchase.receipt, googlePurchase.purchaseToken);
    7.     }
    8. ...
    9. }
    10.  
    and googlePurchase == null

    Any ideas how to make hot fix?
     
    nicholasr likes this.
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sorry I do not have an immediate suggestion. I'll pass this along
     
  5. k_belonogov

    k_belonogov

    Joined:
    Jan 12, 2016
    Posts:
    10
    Thank you!
    I'll look forward to it.
     
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You bet! If we find something, we will try to include it in an upcoming release.
     
  7. nicholasr

    nicholasr

    Unity Technologies

    Joined:
    Aug 15, 2015
    Posts:
    183
    Thank you for the report @k_belonogov about the crashy behavior - I am also looking, and like Jeff I have not reproduced it. I do want to clarify one detail, to help with the reproduction: the Unity version.

    Q: Is this "2020.1.17.f1"?

    It's listed as "2020.17.f1" here, and there is no 2020.17.f1: https://unity3d.com/get-unity/download/archive

    Discussion - TL;DR no joy, so far:

    In my testing I've been able to slow-purchase in multiple scenarios (background, wait, screen off, wifi off, kill app), successfully; I've not crashed / repro'd yet.

    As you noticed in the code there is an "OnPurchaseOk" method, and that is crashing in the scenario reported. The dangling object reference message by "UnityEngine.AndroidJavaProxy.Invoke" is essentially a null pointer exception / segmentation violation, but for backing native Java objects. E.g. the C# is using an underlying native Java object (or two) to satisfy part of its purchasing logic. It uses the AndroidJavaObject feature. If the Object is deallocated during runtime, or is always null from the start, then we will see these types of errors.

    To clarify an aspect of this report, the observation about "MakeGooglePurchase" returning "null" is right, and also that the code is currently not protected against that allocation failure. However this will not generate the error message "UnityEngine.AndroidJavaProxy.Invoke" because all the usages of "googlePurchase" inside OnPurchaseOk are trivial accesses of primitive C# fields; the error message would not mention "AndroidJavaProxy" if googlePurchase were null, it would be a trivial C# "NullPointerException".

    The way that I currently see this OnPurchaseOk method will crash, given the preconditions (allocations) implied by the Stack Trace, is:

    * the app is suddenly unable to load a required Java Purchase.PurchaseState Enum type, after it was previously able to load that type, to access the "PURCHASED" Enum field inside OnPurchaseOk's first line. (see the implementation of GooglePurchaseStateEnum.Purchased())

    And I don't know how a Unity app could unload Java types, to make the PURCHASED field become unavailable, from one method to another method. It's not something I've seen a Unity app do, yet. It feels like it is not the bug.

    Deallocation can happen of AndroidJavaObjects, and there are multiple threads in an application, so perhaps there is something going on that way ... however this is not a complete thought. I do not have a hypothetical scenario in mind where one thread could deallocate the Object and then the purchasing logic thread would try to use that same Object, and crash.

    For what it's worth, I'm going to try a test where I BREAK this code, and see if I am incorrect about the AndroidJavaProxy error message point that I made, above. (EDIT: Yeah this only gives me a trivial "NullReferenceException: Object reference not set to an instance of an object" without mention of "UnityEngine.AndroidJavaProxy.Invoke", which is not the crash that's reported here. So it's something else, some other scenario.)
     
    Last edited: Mar 30, 2021
    k_belonogov likes this.
  8. k_belonogov

    k_belonogov

    Joined:
    Jan 12, 2016
    Posts:
    10
    Thanks a lot, nicholasr!

    yes, its 2020.1.17.f1
     
    nicholasr likes this.
  9. k_belonogov

    k_belonogov

    Joined:
    Jan 12, 2016
    Posts:
    10
    Not fixed in 3.1.0
     
    Last edited: May 7, 2021
  10. MaxShmarov

    MaxShmarov

    Joined:
    Nov 30, 2020
    Posts:
    1
    @nicholasr @JeffDUnity3D
    Hi, I have the same error. I am using Unity IAP v4.1.2 and Unity 2020.3.15f2. Also, I am using the revenue cat SDK for subscriptions. When I buy a subscription on an Android device, I get a null reference exception.

    Stacktrace:
    UnityEngine.Purchasing.GooglePurchaseUpdatedListener.OnPurchaseOk (UnityEngine.Purchasing.Models.GooglePurchase googlePurchase) (at <00000000000000000000000000000000>:0)
    System.Action`1[T].Invoke (T obj) (at <00000000000000000000000000000000>:0)
    UnityEngine.Purchasing.GooglePurchaseUpdatedListener.ApplyOnPurchases (UnityEngine.AndroidJavaObject purchasesList, System.Action`1[T] action) (at <00000000000000000000000000000000>:0)
    System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <00000000000000000000000000000000>:0)
    UnityEngine.AndroidJavaProxy.Invoke (System.String methodName, System.Object[] args) (at <00000000000000000000000000000000>:0)
    UnityEngine._AndroidJNIHelper.InvokeJavaProxyMethod (UnityEngine.AndroidJavaProxy proxy, System.IntPtr jmethodName, System.IntPtr jargs) (at <00000000000000000000000000000000>:0)
    Rethrow as TargetInvocationException: UnityEngine.Purchasing.GooglePurchaseUpdatedListener.onPurchasesUpdated(UnityEngine.AndroidJavaObject,UnityEngine.AndroidJavaObject)
    UnityEngine.AndroidJavaProxy.Invoke (System.String methodName, System.Object[] args) (at <00000000000000000000000000000000>:0)
    UnityEngine._AndroidJNIHelper.InvokeJavaProxyMethod (UnityEngine.AndroidJavaProxy proxy, System.IntPtr jmethodName, System.IntPtr jargs) (at <00000000000000000000000000000000>:0)
     
  11. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    We would not be able to support revenue cat SDK (actually I have not heard of it). Please test Unity IAP without it. It looks like you might have duplicate Google libraries in your project.