From f5393f1c265d3a1a4e969cc0daa317e3af4b66de Mon Sep 17 00:00:00 2001 From: xiangyang Date: Tue, 15 Dec 2020 14:19:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3=E5=9C=A8Visit?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=89=8D=E5=8F=91=E9=80=81=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=AF=BC=E8=87=B4sessionId=E4=B8=8D=E6=AD=A3=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../autotest/tracker/SessionEventsTest.java | 78 ++++++++++++++++--- .../sdk/track/ipc/MultiProcessDataSharer.java | 7 +- .../sdk/track/providers/SessionProvider.java | 14 +++- .../android/sdk/track/utils/SystemUtil.java | 26 +++++++ 4 files changed, 110 insertions(+), 15 deletions(-) diff --git a/demos/demo/src/androidTest/java/com/growingio/autotest/tracker/SessionEventsTest.java b/demos/demo/src/androidTest/java/com/growingio/autotest/tracker/SessionEventsTest.java index cbc570b4..6ef6a090 100644 --- a/demos/demo/src/androidTest/java/com/growingio/autotest/tracker/SessionEventsTest.java +++ b/demos/demo/src/androidTest/java/com/growingio/autotest/tracker/SessionEventsTest.java @@ -24,8 +24,8 @@ import android.view.WindowManager; import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ActivityScenario; import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; @@ -34,6 +34,7 @@ import com.google.common.truth.Truth; import com.growingio.android.sdk.track.BuildConfig; import com.growingio.android.sdk.track.GrowingTracker; +import com.growingio.android.sdk.track.data.PersistentDataProvider; import com.growingio.android.sdk.track.providers.ConfigurationProvider; import com.growingio.autotest.EventsTest; import com.growingio.autotest.TestTrackConfiguration; @@ -46,7 +47,6 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,9 +67,6 @@ public class SessionEventsTest extends EventsTest { private String mLoginUserId; private long mVisitTimestamp; - @Rule - public ActivityScenarioRule scenarioRule = new ActivityScenarioRule<>(MainActivity.class); - @BeforeAppOnCreate public static void beforeAppOnCreate() { DataHelper.deleteAllData(); @@ -149,10 +146,11 @@ protected void onReceivedAppClosedEvents(JSONArray jsonArray) throws JSONExcepti } } }); + ActivityScenario scenario = ActivityScenario.launch(MainActivity.class); Awaiter.untilTrue(receivedVisit); //To State STOP - scenarioRule.getScenario().moveToState(Lifecycle.State.CREATED); + scenario.moveToState(Lifecycle.State.CREATED); Awaiter.untilTrue(receivedAppClosed); receivedAppClosed.set(false); @@ -171,9 +169,9 @@ protected void onReceivedAppClosedEvents(JSONArray jsonArray) throws JSONExcepti } }); //To State RESUMED - scenarioRule.getScenario().moveToState(Lifecycle.State.RESUMED); + scenario.moveToState(Lifecycle.State.RESUMED); //To State STOP - scenarioRule.getScenario().moveToState(Lifecycle.State.CREATED); + scenario.moveToState(Lifecycle.State.CREATED); Awaiter.untilTrue(receivedAppClosed); receivedVisit.set(false); @@ -205,10 +203,10 @@ protected void onReceivedAppClosedEvents(JSONArray jsonArray) throws JSONExcepti Uninterruptibles.sleepUninterruptibly(delayTime * 1000 + 1, TimeUnit.MILLISECONDS); //To State RESUMED - scenarioRule.getScenario().moveToState(Lifecycle.State.RESUMED); + scenario.moveToState(Lifecycle.State.RESUMED); Awaiter.untilTrue(receivedVisit); //To State DESTROYED - scenarioRule.getScenario().moveToState(Lifecycle.State.DESTROYED); + scenario.moveToState(Lifecycle.State.DESTROYED); Awaiter.untilTrue(receivedAppClosed); } @@ -239,6 +237,7 @@ protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { } } }); + ActivityScenario scenario = ActivityScenario.launch(MainActivity.class); Awaiter.untilTrue(receivedVisit); resendVisitEventLoginUserIdFirstFromNull2NotNull(); @@ -248,6 +247,7 @@ protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { resendVisitEventLoginUserIdFromNull2New(); resendVisitEventLoginUserIdFromNotNull2Same(); resendVisitEventLoginUserIdFromNotNull2New(); + scenario.close(); } private void resendVisitEventLoginUserIdFromNull2New() { @@ -360,6 +360,7 @@ protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { receivedVisit.set(true); } }); + ActivityScenario scenario = ActivityScenario.launch(MainActivity.class); Awaiter.untilTrue(receivedVisit); resendVisitEventLocationFromNull2NotNull(); @@ -367,6 +368,7 @@ protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { GrowingTracker.get().cleanLocation(); resendVisitEventLocationFromNull2NotNull(); + scenario.close(); } private void resendVisitEventLocationFromNull2NotNull() { @@ -397,4 +399,60 @@ protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { Uninterruptibles.sleepUninterruptibly(1, SECONDS); } + /** + * 如果在visit事件前触发埋点事件,需要强制补发visit事件后再发送custom事件, + * 且后续Activity生命周期不在触发visit事件 + */ + @Test + public void forceReissueVisitEventTest() { + final AtomicBoolean receivedVisit = new AtomicBoolean(false); + final AtomicBoolean receivedCustom = new AtomicBoolean(false); + String oldSessionId = PersistentDataProvider.get().getSessionId(); + getEventsApiServer().setOnReceivedEventListener(new MockEventsApiServer.OnReceivedEventListener() { + @Override + protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { + checkVisitEvent(jsonArray); + JSONObject visit = jsonArray.getJSONObject(0); + mSessionId = visit.getString("sessionId"); + Truth.assertThat(mSessionId).isNotEmpty(); + Truth.assertThat(oldSessionId).isNotEqualTo(mSessionId); + receivedVisit.set(true); + } + + @Override + protected void onReceivedCustomEvents(JSONArray jsonArray) throws JSONException { + JSONObject jsonObject = jsonArray.getJSONObject(0); + if ("beforeVisitEvent".equals(jsonObject.getString("eventName")) + && mSessionId.equals(jsonObject.getString("sessionId"))) { + receivedCustom.set(true); + } + } + }); + + GrowingTracker.get().trackCustomEvent("beforeVisitEvent"); + Awaiter.untilTrue(receivedVisit); + Awaiter.untilTrue(receivedCustom); + + receivedCustom.set(false); + getEventsApiServer().setOnReceivedEventListener(new MockEventsApiServer.OnReceivedEventListener() { + @Override + protected void onReceivedVisitEvents(JSONArray jsonArray) throws JSONException { + Truth.assertWithMessage("Received Visit Event").fail(); + } + + @Override + protected void onReceivedCustomEvents(JSONArray jsonArray) throws JSONException { + JSONObject jsonObject = jsonArray.getJSONObject(0); + if ("beforeVisitEvent".equals(jsonObject.getString("eventName")) + && mSessionId.equals(jsonObject.getString("sessionId"))) { + receivedCustom.set(true); + } + } + }); + + ActivityScenario scenario = ActivityScenario.launch(MainActivity.class); + GrowingTracker.get().trackCustomEvent("beforeVisitEvent"); + scenario.close(); + } + } diff --git a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/ipc/MultiProcessDataSharer.java b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/ipc/MultiProcessDataSharer.java index 9b153694..2ec77ec9 100644 --- a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/ipc/MultiProcessDataSharer.java +++ b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/ipc/MultiProcessDataSharer.java @@ -286,6 +286,7 @@ public long getAndIncrement(String key, long startValue) { @Override public long getAndAdd(String key, long delta, long startValue) { synchronized (this) { + Logger.d(TAG, "getAndAdd: key = " + key + ", delta = " + delta + ", startValue = " + startValue); awaitLoadedLocked(); final long[] result = new long[1]; SharedEntry entry = mSharedEntries.get(key); @@ -293,13 +294,15 @@ public long getAndAdd(String key, long delta, long startValue) { lockedRun(new Runnable() { @Override public void run() { - result[0] = (long) entry.getValue(mMappedByteBuffer); - entry.putLong(mMappedByteBuffer, result[0] + delta); + result[0] = (long) entry.getValue(mMappedByteBuffer) + delta; + entry.putLong(mMappedByteBuffer, result[0]); } }, entry.getPosition(), SharedEntry.MAX_SIZE); + Logger.d(TAG, "getAndAdd: result = " + result[0]); return result[0]; } else { putValue(key, SharedEntry.VALUE_TYPE_LONG, startValue); + Logger.d(TAG, "getAndAdd: return startValue"); return startValue; } } diff --git a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/providers/SessionProvider.java b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/providers/SessionProvider.java index 32c08f52..1f4d4081 100644 --- a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/providers/SessionProvider.java +++ b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/providers/SessionProvider.java @@ -16,9 +16,11 @@ package com.growingio.android.sdk.track.providers; +import android.content.Context; import android.support.annotation.Nullable; import android.text.TextUtils; +import com.growingio.android.sdk.track.ContextProvider; import com.growingio.android.sdk.track.TrackMainThread; import com.growingio.android.sdk.track.data.PersistentDataProvider; import com.growingio.android.sdk.track.events.TrackEventGenerator; @@ -28,6 +30,7 @@ import com.growingio.android.sdk.track.listener.OnUserIdChangedListener; import com.growingio.android.sdk.track.listener.event.ActivityLifecycleEvent; import com.growingio.android.sdk.track.log.Logger; +import com.growingio.android.sdk.track.utils.SystemUtil; import java.util.UUID; @@ -44,12 +47,14 @@ public class SessionProvider implements IActivityLifecycle, OnUserIdChangedListe private long mLatestPauseTime = 0; private long mLatestVisitTime = 0; private volatile String mSessionId; + private final Context mContext; private static class SingleInstance { private static final SessionProvider INSTANCE = new SessionProvider(); } private SessionProvider() { + mContext = ContextProvider.getApplicationContext(); mSessionInterval = ConfigurationProvider.get().getTrackConfiguration().getSessionInterval() * 1000; ActivityStateProvider.get().registerActivityLifecycleListener(this); } @@ -58,8 +63,12 @@ public static SessionProvider get() { return SingleInstance.INSTANCE; } - @TrackThread void checkAndSendVisit(long resumeTime) { + if (mAlreadySendVisit && mLatestPauseTime == 0) { + Logger.w(TAG, "Visit event already send by force reissue"); + return; + } + if (resumeTime - mLatestPauseTime >= mSessionInterval) { String sessionId = refreshSessionId(); generateVisit(sessionId, resumeTime); @@ -101,7 +110,7 @@ public boolean createdSession() { } public void forceReissueVisit() { - if (mAlreadySendVisit || ActivityStateProvider.get().getForegroundActivity() == null) { + if (mAlreadySendVisit || !SystemUtil.isMainProcess(mContext)) { return; } String sessionId = refreshSessionId(); @@ -156,7 +165,6 @@ public void onTrackMainInitSDK() { UserInfoProvider.get().registerUserIdChangedListener(this); } - @Override public void onUserIdChanged(@Nullable String newUserId) { Logger.d(TAG, "onUserIdChanged: newUserId = " + newUserId + ", mLatestNonNullUserId = " + mLatestNonNullUserId); diff --git a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/utils/SystemUtil.java b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/utils/SystemUtil.java index f133c7ee..5185162d 100644 --- a/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/utils/SystemUtil.java +++ b/growingio-tracker-core/src/main/java/com/growingio/android/sdk/track/utils/SystemUtil.java @@ -19,10 +19,18 @@ import android.app.ActivityManager; import android.content.Context; import android.os.Process; +import android.text.TextUtils; +import com.growingio.android.sdk.track.log.Logger; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.util.List; public class SystemUtil { + private static final String TAG = "SystemUtil"; + private SystemUtil() { } @@ -41,4 +49,22 @@ public static void killAppProcess(Context context) { Process.killProcess(Process.myPid()); System.exit(0); } + + public static String getProcessName() { + try { + File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline"); + BufferedReader mBufferedReader = new BufferedReader(new FileReader(file)); + String processName = mBufferedReader.readLine().trim(); + mBufferedReader.close(); + return processName; + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + public static boolean isMainProcess(Context context) { + String processName = getProcessName(); + return !TextUtils.isEmpty(processName) && processName.equals(context.getPackageName()); + } }