Home | History | Annotate | Download | only in admin
      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 android.app.admin;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.Nullable;
     21 import android.os.Build;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 
     25 import org.xmlpull.v1.XmlPullParser;
     26 import org.xmlpull.v1.XmlSerializer;
     27 
     28 import java.io.IOException;
     29 import java.lang.annotation.Retention;
     30 import java.lang.annotation.RetentionPolicy;
     31 import java.util.Objects;
     32 
     33 /**
     34  * A class containing information about a pending system update.
     35  */
     36 public final class SystemUpdateInfo implements Parcelable {
     37 
     38     /**
     39      * Represents it is unknown whether the system update is a security patch.
     40      */
     41     public static final int SECURITY_PATCH_STATE_UNKNOWN = 0;
     42 
     43     /**
     44      * Represents the system update is not a security patch.
     45      */
     46     public static final int SECURITY_PATCH_STATE_FALSE = 1;
     47 
     48     /**
     49      * Represents the system update is a security patch.
     50      */
     51     public static final int SECURITY_PATCH_STATE_TRUE = 2;
     52 
     53     /** @hide */
     54     @Retention(RetentionPolicy.SOURCE)
     55     @IntDef(prefix = { "SECURITY_PATCH_STATE_" }, value = {
     56             SECURITY_PATCH_STATE_FALSE,
     57             SECURITY_PATCH_STATE_TRUE,
     58             SECURITY_PATCH_STATE_UNKNOWN
     59     })
     60     public @interface SecurityPatchState {}
     61 
     62     private static final String ATTR_RECEIVED_TIME = "received-time";
     63     private static final String ATTR_SECURITY_PATCH_STATE = "security-patch-state";
     64     // Tag used to store original build fingerprint to detect when the update is applied.
     65     private static final String ATTR_ORIGINAL_BUILD = "original-build";
     66 
     67     private final long mReceivedTime;
     68     @SecurityPatchState
     69     private final int mSecurityPatchState;
     70 
     71     private SystemUpdateInfo(long receivedTime, @SecurityPatchState int securityPatchState) {
     72         this.mReceivedTime = receivedTime;
     73         this.mSecurityPatchState = securityPatchState;
     74     }
     75 
     76     private SystemUpdateInfo(Parcel in) {
     77         mReceivedTime = in.readLong();
     78         mSecurityPatchState = in.readInt();
     79     }
     80 
     81     /** @hide */
     82     @Nullable
     83     public static SystemUpdateInfo of(long receivedTime) {
     84         return receivedTime == -1
     85                 ? null : new SystemUpdateInfo(receivedTime, SECURITY_PATCH_STATE_UNKNOWN);
     86     }
     87 
     88     /** @hide */
     89     @Nullable
     90     public static SystemUpdateInfo of(long receivedTime, boolean isSecurityPatch) {
     91         return receivedTime == -1 ? null : new SystemUpdateInfo(receivedTime,
     92                 isSecurityPatch ? SECURITY_PATCH_STATE_TRUE : SECURITY_PATCH_STATE_FALSE);
     93     }
     94 
     95     /**
     96      * Gets time when the update was first available in milliseconds since midnight, January 1,
     97      * 1970 UTC.
     98      * @return Time in milliseconds as given by {@link System#currentTimeMillis()}
     99      */
    100     public long getReceivedTime() {
    101         return mReceivedTime;
    102     }
    103 
    104     /**
    105      * Gets whether the update is a security patch.
    106      * @return {@link #SECURITY_PATCH_STATE_FALSE}, {@link #SECURITY_PATCH_STATE_TRUE}, or
    107      *         {@link #SECURITY_PATCH_STATE_UNKNOWN}.
    108      */
    109     @SecurityPatchState
    110     public int getSecurityPatchState() {
    111         return mSecurityPatchState;
    112     }
    113 
    114     public static final Creator<SystemUpdateInfo> CREATOR =
    115             new Creator<SystemUpdateInfo>() {
    116                 @Override
    117                 public SystemUpdateInfo createFromParcel(Parcel in) {
    118                     return new SystemUpdateInfo(in);
    119                 }
    120 
    121                 @Override
    122                 public SystemUpdateInfo[] newArray(int size) {
    123                     return new SystemUpdateInfo[size];
    124                 }
    125             };
    126 
    127     /** @hide */
    128     public void writeToXml(XmlSerializer out, String tag) throws IOException {
    129         out.startTag(null, tag);
    130         out.attribute(null, ATTR_RECEIVED_TIME, String.valueOf(mReceivedTime));
    131         out.attribute(null, ATTR_SECURITY_PATCH_STATE, String.valueOf(mSecurityPatchState));
    132         out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
    133         out.endTag(null, tag);
    134     }
    135 
    136     /** @hide */
    137     @Nullable
    138     public static SystemUpdateInfo readFromXml(XmlPullParser parser) {
    139         // If an OTA has been applied (build fingerprint has changed), discard stale info.
    140         final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
    141         if (!Build.FINGERPRINT.equals(buildFingerprint)) {
    142             return null;
    143         }
    144         final long receivedTime =
    145                 Long.parseLong(parser.getAttributeValue(null, ATTR_RECEIVED_TIME));
    146         final int securityPatchState =
    147                 Integer.parseInt(parser.getAttributeValue(null, ATTR_SECURITY_PATCH_STATE));
    148         return new SystemUpdateInfo(receivedTime, securityPatchState);
    149     }
    150 
    151     @Override
    152     public int describeContents() {
    153         return 0;
    154     }
    155 
    156     @Override
    157     public void writeToParcel(Parcel dest, int flags) {
    158         dest.writeLong(getReceivedTime());
    159         dest.writeInt(getSecurityPatchState());
    160     }
    161 
    162     @Override
    163     public String toString() {
    164         return String.format("SystemUpdateInfo (receivedTime = %d, securityPatchState = %s)",
    165                 mReceivedTime, securityPatchStateToString(mSecurityPatchState));
    166     }
    167 
    168     private static String securityPatchStateToString(@SecurityPatchState int state) {
    169         switch (state) {
    170             case SECURITY_PATCH_STATE_FALSE:
    171                 return "false";
    172             case SECURITY_PATCH_STATE_TRUE:
    173                 return "true";
    174             case SECURITY_PATCH_STATE_UNKNOWN:
    175                 return "unknown";
    176             default:
    177                 throw new IllegalArgumentException("Unrecognized security patch state: " + state);
    178         }
    179     }
    180 
    181     @Override
    182     public boolean equals(Object o) {
    183         if (this == o) return true;
    184         if (o == null || getClass() != o.getClass()) return false;
    185         SystemUpdateInfo that = (SystemUpdateInfo) o;
    186         return mReceivedTime == that.mReceivedTime
    187                 && mSecurityPatchState == that.mSecurityPatchState;
    188     }
    189 
    190     @Override
    191     public int hashCode() {
    192         return Objects.hash(mReceivedTime, mSecurityPatchState);
    193     }
    194 }
    195