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