• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include <sys/stat.h>   // umask
18 #include <sys/types.h>  // umask
19 
20 #include <fstream>
21 #include <memory>
22 #include <ostream>
23 #include <string>
24 #include <vector>
25 
26 #include "androidfw/ResourceTypes.h"
27 #include "idmap2/BinaryStreamVisitor.h"
28 #include "idmap2/CommandLineOptions.h"
29 #include "idmap2/FileUtils.h"
30 #include "idmap2/Idmap.h"
31 #include "idmap2/PolicyUtils.h"
32 #include "idmap2/SysTrace.h"
33 
34 using android::idmap2::BinaryStreamVisitor;
35 using android::idmap2::CommandLineOptions;
36 using android::idmap2::Error;
37 using android::idmap2::Idmap;
38 using android::idmap2::OverlayResourceContainer;
39 using android::idmap2::Result;
40 using android::idmap2::TargetResourceContainer;
41 using android::idmap2::Unit;
42 using android::idmap2::utils::kIdmapFilePermissionMask;
43 using android::idmap2::utils::PoliciesToBitmaskResult;
44 using android::idmap2::utils::UidHasWriteAccessToPath;
45 
46 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
47 using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
48 
Create(const std::vector<std::string> & args)49 Result<Unit> Create(const std::vector<std::string>& args) {
50   SYSTRACE << "Create " << args;
51   std::string target_apk_path;
52   std::string overlay_apk_path;
53   std::string idmap_path;
54   std::string overlay_name;
55   std::vector<std::string> policies;
56   bool ignore_overlayable = false;
57 
58   const CommandLineOptions opts =
59       CommandLineOptions("idmap2 create")
60           .MandatoryOption("--target-apk-path",
61                            "input: path to apk which will have its resources overlaid",
62                            &target_apk_path)
63           .MandatoryOption("--overlay-apk-path",
64                            "input: path to apk which contains the new resource values",
65                            &overlay_apk_path)
66           .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
67           .OptionalOption("--overlay-name", "input: the value of android:name of the overlay",
68                           &overlay_name)
69           .OptionalOption("--policy",
70                           "input: an overlayable policy this overlay fulfills "
71                           "(if none are supplied, the overlay policy will default to \"public\")",
72                           &policies)
73           .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
74                         &ignore_overlayable);
75   const auto opts_ok = opts.Parse(args);
76   if (!opts_ok) {
77     return opts_ok.GetError();
78   }
79 
80   const uid_t uid = getuid();
81   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
82     return Error("uid %d does not have write access to %s", uid, idmap_path.c_str());
83   }
84 
85   PolicyBitmask fulfilled_policies = 0;
86   auto conv_result = PoliciesToBitmaskResult(policies);
87   if (conv_result) {
88     fulfilled_policies |= *conv_result;
89   } else {
90     return conv_result.GetError();
91   }
92 
93   if (fulfilled_policies == 0) {
94     fulfilled_policies |= PolicyFlags::PUBLIC;
95   }
96 
97   const auto target = TargetResourceContainer::FromPath(target_apk_path);
98   if (!target) {
99     return Error("failed to load target '%s'", target_apk_path.c_str());
100   }
101 
102   const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
103   if (!overlay) {
104     return Error("failed to load apk overlay '%s'", overlay_apk_path.c_str());
105   }
106 
107   const auto idmap = Idmap::FromContainers(**target, **overlay, overlay_name, fulfilled_policies,
108                                            !ignore_overlayable);
109   if (!idmap) {
110     return Error(idmap.GetError(), "failed to create idmap");
111   }
112 
113   umask(kIdmapFilePermissionMask);
114   std::ofstream fout(idmap_path);
115   if (fout.fail()) {
116     return Error("failed to open idmap path '%s'", idmap_path.c_str());
117   }
118 
119   BinaryStreamVisitor visitor(fout);
120   (*idmap)->accept(&visitor);
121   fout.close();
122   if (fout.fail()) {
123     return Error("failed to write to idmap path '%s'", idmap_path.c_str());
124   }
125 
126   return Unit{};
127 }
128