1 /*
2  * Copyright (C) 2017 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 com.android.server.timezone;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.DataInputStream;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.util.Arrays;
25 
26 /**
27  * A deserialized version of the byte[] sent to the time zone update application to identify a
28  * triggered time zone update check. It encodes the optimistic lock ID used to detect
29  * concurrent checks and the minimal package versions that will have been checked.
30  */
31 final class CheckToken {
32 
33     final int mOptimisticLockId;
34     final PackageVersions mPackageVersions;
35 
CheckToken(int optimisticLockId, PackageVersions packageVersions)36     CheckToken(int optimisticLockId, PackageVersions packageVersions) {
37         this.mOptimisticLockId = optimisticLockId;
38 
39         if (packageVersions == null) {
40             throw new NullPointerException("packageVersions == null");
41         }
42         this.mPackageVersions = packageVersions;
43     }
44 
toByteArray()45     byte[] toByteArray() {
46         ByteArrayOutputStream baos = new ByteArrayOutputStream(12 /* (3 * sizeof(int)) */);
47         try (DataOutputStream dos = new DataOutputStream(baos)) {
48             dos.writeInt(mOptimisticLockId);
49             dos.writeLong(mPackageVersions.mUpdateAppVersion);
50             dos.writeLong(mPackageVersions.mDataAppVersion);
51         } catch (IOException e) {
52             throw new RuntimeException("Unable to write into a ByteArrayOutputStream", e);
53         }
54         return baos.toByteArray();
55     }
56 
fromByteArray(byte[] tokenBytes)57     static CheckToken fromByteArray(byte[] tokenBytes) throws IOException {
58         ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
59         try (DataInputStream dis = new DataInputStream(bais)) {
60             int versionId = dis.readInt();
61             long updateAppVersion = dis.readLong();
62             long dataAppVersion = dis.readLong();
63             return new CheckToken(versionId, new PackageVersions(updateAppVersion, dataAppVersion));
64         }
65     }
66 
67     @Override
equals(Object o)68     public boolean equals(Object o) {
69         if (this == o) {
70             return true;
71         }
72         if (o == null || getClass() != o.getClass()) {
73             return false;
74         }
75 
76         CheckToken checkToken = (CheckToken) o;
77 
78         if (mOptimisticLockId != checkToken.mOptimisticLockId) {
79             return false;
80         }
81         return mPackageVersions.equals(checkToken.mPackageVersions);
82     }
83 
84     @Override
hashCode()85     public int hashCode() {
86         int result = mOptimisticLockId;
87         result = 31 * result + mPackageVersions.hashCode();
88         return result;
89     }
90 
91     @Override
toString()92     public String toString() {
93         return "Token{" +
94                 "mOptimisticLockId=" + mOptimisticLockId +
95                 ", mPackageVersions=" + mPackageVersions +
96                 '}';
97     }
98 }
99