1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.util; 18 19 /** 20 * Utilities to manage an info change seq id to ensure the update is in sync between client and 21 * system server. This should be used for info that can be updated though multiple IPC channel. 22 * 23 * To use it: 24 * 1. The system server should store the current seq as the source of truth, with initializing to 25 * {@link #getInitSeq}. 26 * 2. Whenever a newer info needs to be sent to the client side, the system server should first 27 * update its seq with {@link #getNextSeq}, then send the new info with the new seq to the client. 28 * 3. On the client side, when receiving a new info, it should only consume it if it is not stale by 29 * checking {@link #isIncomingSeqStale}. 30 * 31 * @hide 32 */ 33 public final class SequenceUtils { 34 SequenceUtils()35 private SequenceUtils() { 36 } 37 38 /** 39 * Returns {@code true} if the incomingSeq is stale, which means the client should not consume 40 * it. 41 */ isIncomingSeqStale(int curSeq, int incomingSeq)42 public static boolean isIncomingSeqStale(int curSeq, int incomingSeq) { 43 if (curSeq == getInitSeq()) { 44 // curSeq can be set to the initial seq in the following cases: 45 // 1. The client process/field is newly created/recreated. 46 // 2. The field is not managed by the system server, such as WindowlessWindowManager. 47 // The client should always consume the incoming in these cases. 48 return false; 49 } 50 // Convert to long for comparison. 51 final long diff = (long) incomingSeq - curSeq; 52 // When diff is 0, allow client to consume. 53 // When there has been a sufficiently large jump, assume the sequence has wrapped around. 54 return (diff < 0 && diff > Integer.MIN_VALUE) || diff > Integer.MAX_VALUE; 55 } 56 57 /** Returns the initial seq. */ getInitSeq()58 public static int getInitSeq() { 59 return Integer.MIN_VALUE; 60 } 61 62 /** Returns the next seq. */ getNextSeq(int seq)63 public static int getNextSeq(int seq) { 64 return seq == Integer.MAX_VALUE 65 // Skip the initial seq, so that when the app process is relaunched, the incoming 66 // seq from the server is always treated as newer. 67 ? getInitSeq() + 1 68 : ++seq; 69 } 70 } 71